Update doc/samples/test of windows.security

This commit is contained in:
hakril
2018-12-21 15:26:29 +01:00
parent 986664d01f
commit 79ff18e06f
5 changed files with 641 additions and 23 deletions
+255
View File
@@ -0,0 +1,255 @@
``windows.security`` -- Security Descriptor & related
*****************************************************
.. warning:
Foutre les token ici ?
Ca a du sens https://docs.microsoft.com/en-us/windows/desktop/secauthz/access-control-components
ACCESS CONTROL TOUT CA..
Les deux vont bien ensemble..
.. module:: windows.security
SecurityDescriptor
""""""""""""""""""
.. autoclass:: SecurityDescriptor
Acl
"""
.. autoclass:: Acl
:special-members: __len__, __iter__
.. _security_ace:
Ace
"""
The ACE are regrouped in two categories.
The DACL related ACEs:
- :class:`AccessAllowedACE`
- :class:`AccessDeniedACE`
- :class:`AccessAllowedCallbackACE`
- :class:`AccessDeniedCallbackACE`
- :class:`AccessAllowedObjectACE`
- :class:`AccessDeniedObjectACE`
- :class:`AccessAllowedCallbackObjectACE`
- :class:`AccessDeniedCallbackObjectACE`
The SACL related ACEs:
- :class:`SystemAuditACE`
- :class:`SystemAlarmACE`
- :class:`SystemAuditObjectACE`
- :class:`SystemAlarmObjectACE`
- :class:`SystemAuditCallbackACE`
- :class:`SystemAlarmCallbackACE`
- :class:`SystemAuditCallbackObjectACE`
- :class:`SystemAlarmCallbackObjectACE`
- :class:`SystemMandatoryLabelACE`
- :class:`SystemResourceAttributeACE`
- :class:`SystemScopedPolicyIDACE`
- :class:`SystemProcessTrustLabelACE`
Ace classes
'''''''''''
AccessAllowedACE
~~~~~~~~~~~~~~~~
.. autoclass:: AccessAllowedACE
:show-inheritance:
:inherited-members:
AccessDeniedACE
~~~~~~~~~~~~~~~
.. autoclass:: AccessDeniedACE
:show-inheritance:
:inherited-members:
AccessAllowedCallbackACE
~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: AccessAllowedCallbackACE
:show-inheritance:
:inherited-members:
AccessDeniedCallbackACE
~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: AccessDeniedCallbackACE
:show-inheritance:
:inherited-members:
AccessAllowedObjectACE
~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: AccessAllowedObjectACE
:show-inheritance:
:inherited-members:
AccessDeniedObjectACE
~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: AccessDeniedObjectACE
:show-inheritance:
:inherited-members:
AccessAllowedCallbackObjectACE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: AccessAllowedCallbackObjectACE
:show-inheritance:
:inherited-members:
AccessDeniedCallbackObjectACE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: AccessDeniedCallbackObjectACE
:show-inheritance:
:inherited-members:
SystemAuditACE
~~~~~~~~~~~~~~
.. autoclass:: SystemAuditACE
:show-inheritance:
:inherited-members:
SystemAlarmACE
~~~~~~~~~~~~~~
.. autoclass:: SystemAlarmACE
:show-inheritance:
:inherited-members:
SystemAuditObjectACE
~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemAuditObjectACE
:show-inheritance:
:inherited-members:
SystemAlarmObjectACE
~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemAlarmObjectACE
:show-inheritance:
:inherited-members:
SystemAuditCallbackACE
~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemAuditCallbackACE
:show-inheritance:
:inherited-members:
SystemAlarmCallbackACE
~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemAlarmCallbackACE
:show-inheritance:
:inherited-members:
SystemAuditCallbackObjectACE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemAuditCallbackObjectACE
:show-inheritance:
:inherited-members:
SystemAlarmCallbackObjectACE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemAlarmCallbackObjectACE
:show-inheritance:
:inherited-members:
SystemMandatoryLabelACE
~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemMandatoryLabelACE
:show-inheritance:
:inherited-members:
SystemResourceAttributeACE
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemResourceAttributeACE
:show-inheritance:
:inherited-members:
SystemScopedPolicyIDACE
~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemScopedPolicyIDACE
:show-inheritance:
:inherited-members:
SystemProcessTrustLabelACE
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autoclass:: SystemProcessTrustLabelACE
:show-inheritance:
:inherited-members:
Ace common base
"""""""""""""""
These classes are internals and here for completness sake.
You should not need to instanciate/use them directly.
AceHeader
'''''''''
.. autoclass:: AceHeader
AceBase
'''''''
.. autoclass:: AceBase
MaskAndSidACE
'''''''''''''
.. autoclass:: MaskAndSidACE
CallbackACE
'''''''''''
.. autoclass:: CallbackACE
ObjectRelatedACE
''''''''''''''''
.. autoclass:: ObjectRelatedACE
+34
View File
@@ -0,0 +1,34 @@
import sys
import windows.security
TARGET = r"C:\windows\notepad.exe" # On WIN10 (at least) notepad.exe has a AuditACE
if not windows.current_process.token.elevated:
print(ValueError("This sample should be run as admin to demonstration SACL access"))
print("")
print("[NO-PRIV] Querying <{0}> SecurityDescriptor without SACL".format(TARGET))
sd = windows.security.SecurityDescriptor.from_filename(TARGET)
print("sacl = {0}".format(sd.sacl))
print("")
print("[NO-PRIV] Querying <{0}> SecurityDescriptor with SACL".format(TARGET))
try:
sd = windows.security.SecurityDescriptor.from_filename(TARGET, query_sacl=True)
print("sacl = {0}".format(sd.sacl))
except WindowsError as e:
print(e)
print("")
print("Enabling <SeSecurityPrivilege>")
try:
windows.current_process.token.enable_privilege("SeSecurityPrivilege")
except ValueError as e:
print("[ERROR] {0}".format(e))
exit(1)
print("")
print("[PRIV] Querying <{0}> SecurityDescriptor with SACL".format(TARGET))
sd = windows.security.SecurityDescriptor.from_filename(TARGET, query_sacl=True)
print("sacl = {0}".format(sd.sacl))
print(list(sd.sacl))
+24
View File
@@ -0,0 +1,24 @@
import windows.security
SDDL = "O:BAG:AND:(A;OI;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)(D;CIIO;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
sd = windows.security.SecurityDescriptor.from_string(SDDL)
print("Security descriptor is: {0}".format(sd))
print("Owner: {0}".format(sd.owner))
print(" - lookup: {0}".format(windows.security.lookup_sid(sd.owner)))
print("Group: {0}".format(sd.group))
print(" - lookup: {0}".format(windows.security.lookup_sid(sd.group)))
dacl = sd.dacl
print("Dacl: {0}".format(dacl))
for i, ace in enumerate(dacl):
print("")
print(" ACE [{0}]: {1}".format(i, ace))
print(" - Header-AceType: {0}".format(ace.Header.AceType))
print(" - Header-AceFlags: {0}".format(ace.Header.AceFlags))
print(" - Header-flags: {0}".format(ace.Header.flags))
print(" - Mask: {0}".format(ace.Mask))
print(" - mask: {0}".format(ace.mask))
print(" - Sid: {0}".format(ace.sid))
+8
View File
@@ -19,6 +19,13 @@ TEST_SDDL = [
def test_security_descriptor_from_string(sddl):
sd = SecurityDescriptor.from_string(sddl)
def test_empty_security_descriptor():
esd = SecurityDescriptor.from_string("")
assert esd.owner is None # Should NOT be NULL PSID but None
assert esd.group is None # Should NOT be NULL PSID but None
assert esd.dacl is None
assert esd.sacl is None
def test_pacl_object():
SDDL = "O:ANG:S-1-2-3D:(A;;;;;S-1-42-42)(A;;;;;S-1-42-43)(A;;;;;S-1-42-44)"
@@ -193,3 +200,4 @@ def test_conditional_ace_applicationdata(sddl, expected_value):
assert expected_value in appdata.replace("\x00", "")
+320 -23
View File
@@ -6,15 +6,171 @@ import windows.generated_def as gdef
from windows import winproxy
# Temporary ? real API ?
# Mov to utils ?
def lookup_sid(psid):
usernamesize = gdef.DWORD(0x1000)
computernamesize = gdef.DWORD(0x1000)
username = ctypes.c_buffer(usernamesize.value)
computername = ctypes.c_buffer(computernamesize.value)
username = ctypes.create_unicode_buffer(usernamesize.value)
computername = ctypes.create_unicode_buffer(computernamesize.value)
peUse = gdef.SID_NAME_USE()
winproxy.LookupAccountSidA(None, psid, username, usernamesize, computername, computernamesize, peUse)
winproxy.LookupAccountSidW(None, psid, username, usernamesize, computername, computernamesize, peUse)
return computername[:computernamesize.value], username[:usernamesize.value]
# Specific access right
FILE_ACCESS_RIGHT = gdef.FlagMapper(
gdef.FILE_READ_DATA,
gdef.FILE_WRITE_DATA,
gdef.FILE_APPEND_DATA,
gdef.FILE_READ_EA,
gdef.FILE_WRITE_EA,
gdef.FILE_EXECUTE,
gdef.FILE_READ_ATTRIBUTES,
gdef.FILE_WRITE_ATTRIBUTES
)
DIRECTORY_ACCESS_RIGHT = gdef.FlagMapper(
gdef.FILE_LIST_DIRECTORY,
gdef.FILE_ADD_FILE,
gdef.FILE_ADD_SUBDIRECTORY,
gdef.FILE_READ_EA,
gdef.FILE_WRITE_EA,
gdef.FILE_TRAVERSE,
gdef.FILE_DELETE_CHILD,
gdef.FILE_READ_ATTRIBUTES,
gdef.FILE_WRITE_ATTRIBUTES,
)
NAMED_PIPE_ACCESS_RIGHT = gdef.FlagMapper(
gdef.FILE_READ_DATA,
gdef.FILE_WRITE_DATA,
gdef.FILE_CREATE_PIPE_INSTANCE,
gdef.FILE_READ_ATTRIBUTES,
gdef.FILE_WRITE_ATTRIBUTES,
)
TOKEN_ACCESS_RIGHT = gdef.FlagMapper(
gdef.TOKEN_ASSIGN_PRIMARY,
gdef.TOKEN_DUPLICATE,
gdef.TOKEN_IMPERSONATE,
gdef.TOKEN_QUERY,
gdef.TOKEN_QUERY_SOURCE,
gdef.TOKEN_ADJUST_PRIVILEGES,
gdef.TOKEN_ADJUST_GROUPS,
gdef.TOKEN_ADJUST_DEFAULT,
gdef.TOKEN_ADJUST_SESSIONID,
)
CLUSTER_API_ACCESS_RIGH = gdef.FlagMapper(
gdef.CLUSAPI_READ_ACCESS,
gdef.CLUSAPI_CHANGE_ACCESS,
gdef.CLUSAPI_NO_ACCESS,
)
FAX_ACCESS_RIGHT = gdef.FlagMapper(
gdef.FAX_JOB_SUBMIT,
gdef.FAX_JOB_QUERY,
gdef.FAX_CONFIG_QUERY,
gdef.FAX_CONFIG_SET,
gdef.FAX_PORT_QUERY,
gdef.FAX_PORT_SET,
gdef.FAX_JOB_MANAGE,
)
CALLBACK_ACCESS_RIGHT = gdef.FlagMapper(
gdef.CALLBACK_MODIFY_STATE,
)
MUTANT_ACCESS_RIGHT = gdef.FlagMapper(
gdef.MUTANT_QUERY_STATE,
)
EVENT_ACCESS_RIGHT = gdef.FlagMapper(
gdef.EVENT_QUERY_STATE,
gdef.EVENT_MODIFY_STATE,
)
SEMAPHORE_ACCESS_RIGHT = gdef.FlagMapper(
gdef.SEMAPHORE_QUERY_STATE,
gdef.SEMAPHORE_MODIFY_STATE,
)
SEMAPHORE_ACCESS_RIGHT = gdef.FlagMapper(
gdef.TIMER_QUERY_STATE,
gdef.TIMER_QUERY_STATE,
)
IO_COMPLETION_ACCESS_RIGHT = gdef.FlagMapper(
gdef.IO_COMPLETION_QUERY_STATE,
gdef.IO_COMPLETION_MODIFY_STATE,
)
PORT_ACCESS_RIGHT = gdef.FlagMapper(
gdef.PORT_CONNECT,
)
OBJECT_MANAGER_TYPE_ACCESS_RIGHT = gdef.FlagMapper(
gdef.OBJECT_TYPE_CREATE
)
OBJECT_MANAGER_DIRECTORY_ACCESS_RIGHT = gdef.FlagMapper(
gdef.DIRECTORY_QUERY,
gdef.DIRECTORY_TRAVERSE,
gdef.DIRECTORY_CREATE_OBJECT,
gdef.DIRECTORY_CREATE_SUBDIRECTORY,
)
OBJECT_MANAGER_SIMLINK_ACCESS_RIGHT = gdef.FlagMapper(
gdef.SYMBOLIC_LINK_QUERY,
)
PROCESS_ACCESS_RIGHT = gdef.FlagMapper(
gdef.PROCESS_TERMINATE ,
gdef.PROCESS_CREATE_THREAD ,
gdef.PROCESS_SET_SESSIONID ,
gdef.PROCESS_VM_OPERATION ,
gdef.PROCESS_VM_READ ,
gdef.PROCESS_VM_WRITE ,
gdef.PROCESS_DUP_HANDLE ,
gdef.PROCESS_CREATE_PROCESS ,
gdef.PROCESS_SET_QUOTA ,
gdef.PROCESS_SET_INFORMATION ,
gdef.PROCESS_QUERY_INFORMATION ,
gdef.PROCESS_SUSPEND_RESUME ,
gdef.PROCESS_QUERY_LIMITED_INFORMATION ,
gdef.PROCESS_SET_LIMITED_INFORMATION ,
)
THREAD_ACCESS_RIGHT = gdef.FlagMapper(
gdef.THREAD_TERMINATE,
gdef.THREAD_SUSPEND_RESUME,
gdef.THREAD_GET_CONTEXT,
gdef.THREAD_SET_CONTEXT,
gdef.THREAD_QUERY_INFORMATION,
gdef.THREAD_SET_INFORMATION,
gdef.THREAD_SET_THREAD_TOKEN,
gdef.THREAD_IMPERSONATE,
gdef.THREAD_DIRECT_IMPERSONATION,
)
JOB_ACCESS_RIGHT = gdef.FlagMapper(
gdef.JOB_OBJECT_ASSIGN_PROCESS ,
gdef.JOB_OBJECT_SET_ATTRIBUTES ,
gdef.JOB_OBJECT_QUERY ,
gdef.JOB_OBJECT_TERMINATE ,
gdef.JOB_OBJECT_SET_SECURITY_ATTRIBUTES,
)
KEY_ACCESS_RIGHT = gdef.FlagMapper(
gdef.KEY_QUERY_VALUE ,
gdef.KEY_SET_VALUE ,
gdef.KEY_CREATE_SUB_KEY ,
gdef.KEY_ENUMERATE_SUB_KEYS ,
gdef.KEY_NOTIFY ,
gdef.KEY_CREATE_LINK ,
gdef.KEY_WOW64_64KEY ,
gdef.KEY_WOW64_32KEY ,
# KEY_WOW64_RES (0x0300) # Just a mask of the 2 last
)
# ACE
@@ -47,11 +203,16 @@ class AceHeader(gdef.ACE_HEADER):
@property
def AceType(self):
"""The type of the Ace header"""
raw_type = super(AceHeader, self).AceType
return ACE_CLASS_TYPE_MAPPER[raw_type]
@property
def flags(self):
"""The flags of the Ace header
:type: [:class:`int`] - A list of :class:`int`
"""
return list(self._flags_generator())
def _flags_generator(self):
@@ -71,28 +232,43 @@ class AceHeader(gdef.ACE_HEADER):
class AceBase(object): # Ca ou mettre flags extraction dans le ctypes generated
"""Base object for all ``ACE`` classes. provide access to an improved header"""
@property
def Header(self): # Override the ctypes Header for the struct -> return extended header
"""The Header of the ``ACE``
:type: :class:`AceHeader`
"""
addr = ctypes.addressof(self)
sheader = super(AceBase, type(self)).Header
return AceHeader.from_address(addr + sheader.offset)
class MaskAndSidACE(AceBase):
# "Virtual" ACE for ACE struct with
# ACE_HEADER Header;
# ACCESS_MASK Mask;
# DWORD SidStart;
"""`Virtual` ACE for ACE struct with the following layout:
- ACE_HEADER Header
- ACCESS_MASK Mask
- DWORD SidStart
"""
def _sid_offset(self):
return type(self).SidStart.offset
@property
def sid(self):
"""The sid described by the ``ACE``
:type: :class:`windows.generated_def.winstructs.PSID`
"""
return gdef.PSID(ctypes.addressof(self) + self._sid_offset())
@property
def mask(self):
"""The list of flags described by the ``ACE``
:type: [:class:`int`] - A list of :class:`int`
"""
return list(self._mask_generator())
def _mask_generator(self):
@@ -109,7 +285,12 @@ class MaskAndSidACE(AceBase):
class CallbackACE(MaskAndSidACE):
@property
def application_data(self):
"""FROM : https://msdn.microsoft.com/en-us/library/hh877860.aspx"""
"""The application-specific data
see : https://msdn.microsoft.com/en-us/library/hh877860.aspx
:type: :class:`str`
"""
selfptr = ctypes.cast(ctypes.addressof(self), gdef.PUCHAR)
datastart = ctypes.sizeof(self) + self.sid.size - 4
dataend = self.Header.AceSize
@@ -122,17 +303,29 @@ class ObjectRelatedACE(MaskAndSidACE):
@property
def flags(self):
"""The flags of the ``ACE``
:type: [:class:`int`] - A list of :class:`int`
"""
flags = self.Flags
return [x for x in self.FLAGS_VALUES if flags & x]
@property
def object_type(self):
"""The ``ObjectType`` described in the ACE. ``None`` if `ACE`` has no ``ObjectType``
:type: :class:`~windows.generated_def.winstructs.PSID` or ``None``
"""
if not self.Flags & gdef.ACE_OBJECT_TYPE_PRESENT:
return None
return self.ObjectType
@property
def inherited_object_type(self):
"""The ``InheritedObjectType`` described in the ACE. ``None`` if `ACE`` has no ``InheritedObjectType``
:type: :class:`~windows.generated_def.winstructs.PSID` or ``None``
"""
if not self.Flags & gdef.ACE_INHERITED_OBJECT_TYPE_PRESENT:
return None
if self.Flags & gdef.ACE_OBJECT_TYPE_PRESENT:
@@ -220,7 +413,6 @@ class SystemResourceAttributeACE(MaskAndSidACE, gdef.SYSTEM_RESOURCE_ATTRIBUTE_A
# Sid-size not in the initial struct
sid_size_over = self.sid.size - type(self).SidStart.size
sec_attr_addr = ctypes.addressof(self) + ctypes.sizeof(self) + sid_size_over
return ClaimSecurityAttributeRelativeV1.from_address(sec_attr_addr)
class SystemScopedPolicyIDACE(MaskAndSidACE, gdef.SYSTEM_SCOPED_POLICY_ID_ACE):
@@ -258,7 +450,6 @@ ACE_CLASS_BY_ACE_TYPE = {cls.ACE_TYPE: cls for cls in (
ACE_CLASS_TYPE_MAPPER = gdef.FlagMapper(*ACE_CLASS_BY_ACE_TYPE.keys())
# CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 follow the SYSTEM_RESOURCE_ATTRIBUTE_ACE
# For ACE of type SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE
@@ -322,6 +513,7 @@ class ClaimSecurityAttributeRelativeV1(gdef.CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
# ACL
class Acl(gdef.ACL):
"""All the ``ACE`` returned by :class:`Acl` methods/property are described in the :ref:`Ace section <security_ace>`"""
@property
def size_info(self):
size_info = gdef.ACL_SIZE_INFORMATION()
@@ -329,6 +521,10 @@ class Acl(gdef.ACL):
return size_info
def get_ace(self, i):
"""Retrieve ``ACE`` number ``i``
:return: :class:`Ace`
"""
ace = gdef.PVOID()
winproxy.GetAce(self, i, ace)
# TODO: subclass ACL
@@ -336,9 +532,14 @@ class Acl(gdef.ACL):
@property
def aces(self):
"""The list of ``ACE`` in the ACL :class:`Acl`
:type: [:class:`Ace`] - A list of ACE
"""
return list(self)
def __len__(self):
"""The number of ``ACE`` in the :class:`Acl`"""
return self.AceCount
def __getitem__(self, i):
@@ -350,6 +551,9 @@ class Acl(gdef.ACL):
raise
def __iter__(self):
"""Return an iterable over all the ``ACE`` in the :class:`Acl`
:yield: :class:`Ace`"""
for i in range(self.AceCount):
yield self.get_ace(i)
@@ -359,11 +563,12 @@ class Acl(gdef.ACL):
PAcl = ctypes.POINTER(Acl)
# Security descriptor
class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
"""TODO: free the underliying buffer when not needed anymore
"""A Security Descriptor
for now the underliying memory is never free
.. warning::
TODO: free the underliying buffer when not needed anymore for now the underliying memory is never freed.
"""
DEFAULT_SECURITY_INFORMATION = (
gdef.OWNER_SECURITY_INFORMATION |
@@ -374,14 +579,35 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
gdef.SCOPE_SECURITY_INFORMATION |
gdef.PROCESS_TRUST_LABEL_SECURITY_INFORMATION
)
"""The default ``flags`` value for functions expecting a
`SECURITY_INFORMATION <https://docs.microsoft.com/en-us/windows/desktop/SecAuthZ/security-information>`_.
This value regroups the followings flags:
- ``OWNER_SECURITY_INFORMATION``
- ``GROUP_SECURITY_INFORMATION``
- ``DACL_SECURITY_INFORMATION``
- ``ATTRIBUTE_SECURITY_INFORMATION``
- ``SCOPE_SECURITY_INFORMATION``
- ``PROCESS_TRUST_LABEL_SECURITY_INFORMATION``
.. warning::
Note that the value ``SACL_SECURITY_INFORMATION`` needed to access the SACL is not present as it require the ``SeSecurityPrivilege``.
To query the SACL enable the ``SeSecurityPrivilege`` and use the parameter ``query_sacl=True`` on the functions expecting a ``flags``
see SACL sample
"""
_close_function = winproxy.LocalFree
# def __init__(self, needs_free=True):
# self._needs_free = needs_free
@property
def control(self):
"""The security descriptor control
:type: :class:`~windows.generated_def.winstructs.SECURITY_DESCRIPTOR_CONTROL`
"""
lpdwRevision = gdef.DWORD()
control = gdef.SECURITY_DESCRIPTOR_CONTROL()
winproxy.GetSecurityDescriptorControl(self, control, lpdwRevision)
@@ -389,6 +615,10 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
@property
def revision(self):
"""The security descriptor's revision
:type: :class:`int`
"""
lpdwRevision = gdef.DWORD()
control = gdef.SECURITY_DESCRIPTOR_CONTROL()
winproxy.GetSecurityDescriptorControl(self, control, lpdwRevision)
@@ -396,21 +626,35 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
@property
def owner(self):
"""The owner of the security descriptor
:type: :class:`~windows.generated_def.winstructs.PSID` or ``None``
"""
owner = gdef.PSID()
lpbOwnerDefaulted = gdef.BOOL()
winproxy.GetSecurityDescriptorOwner(self, owner, lpbOwnerDefaulted)
return owner
# Return None of owner is NULL
return owner or None
@property
def group(self):
"""The group of the security descriptor
:type: :class:`~windows.generated_def.winstructs.PSID` or ``None``
"""
group = gdef.PSID()
lpbGroupDefaulted = gdef.BOOL()
winproxy.GetSecurityDescriptorGroup(self, group, lpbGroupDefaulted)
return group
# Return None of group is NULL
return group or None
@property
def dacl(self):
"""The DACL of the security descriptor.
:type: :class:`Acl` or ``None`` if the DACL was ``NULL`` or not present
"""
dacl_present = gdef.BOOL()
pdacl = gdef.PACL()
lpbDaclDefaulted = gdef.BOOL()
@@ -421,6 +665,10 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
@property
def sacl(self):
"""The SACL of the security descriptor. You may need special attention to retrieve it (see :any:`DEFAULT_SECURITY_INFORMATION`)
:type: :class:`Acl` or ``None`` if the SACL was ``NULL`` or not present
"""
sacl_present = gdef.BOOL()
psacl = gdef.PACL()
lpbSaclDefaulted = gdef.BOOL()
@@ -432,6 +680,16 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
# Constructors
@classmethod
def from_string(cls, sddl):
"""Return a new :class:`SecurityDescriptor` from the ``SDDL``.
:returns: :class:`SecurityDescriptor`
.. warning::
At the moment the underliying buffer is never freed.
See `ConvertStringSecurityDescriptorToSecurityDescriptorA <https://docs.microsoft.com/en-us/windows/desktop/api/sddl/nf-sddl-convertstringsecuritydescriptortosecuritydescriptora>`_
"""
self = cls()
winproxy.ConvertStringSecurityDescriptorToSecurityDescriptorA(
sddl,
@@ -443,16 +701,16 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
return self
@classmethod
def _from_name_and_type(cls, objname, objtype, query_sacl=False, security_infos=DEFAULT_SECURITY_INFORMATION):
def _from_name_and_type(cls, objname, objtype, flags=DEFAULT_SECURITY_INFORMATION, query_sacl=False):
self = cls()
if query_sacl:
security_infos |= gdef.SACL_SECURITY_INFORMATION
flags |= gdef.SACL_SECURITY_INFORMATION
winproxy.GetNamedSecurityInfoA(
objname,
objtype,
security_infos,
flags,
None,
None,
None,
@@ -462,10 +720,48 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
return self
@classmethod
def from_filename(cls, filename, query_sacl=False):
return cls._from_name_and_type(filename, gdef.SE_FILE_OBJECT, query_sacl=query_sacl)
def _from_handle_and_type(cls, handle, objtype, flags=DEFAULT_SECURITY_INFORMATION, query_sacl=False):
self = cls()
if query_sacl:
flags |= gdef.SACL_SECURITY_INFORMATION
winproxy.GetSecurityInfo(
handle,
objtype,
flags,
None,
None,
None,
None,
self
)
return self
@classmethod
def from_filename(cls, filename, query_sacl=False, flags=DEFAULT_SECURITY_INFORMATION):
"""Retrieve the security descriptor for the file ``filename``"""
return cls._from_name_and_type(filename, gdef.SE_FILE_OBJECT, flags=flags, query_sacl=query_sacl)
@classmethod
def from_handle(cls, handle, query_sacl=False, flags=DEFAULT_SECURITY_INFORMATION):
"""Retrieve the security descriptor for the kernel object described by``handle``"""
return cls._from_handle_and_type(handle, gdef.SE_KERNEL_OBJECT, flags=flags, query_sacl=query_sacl)
@classmethod
def from_binary(cls, data):
"""Retrieve the security descriptor described by the binary ``data``.
Binary security descriptor can be found in the registry for example
"""
if isinstance(data, basestring):
data = ctypes.c_buffer(data)
return ctypes.cast(data, cls)
def to_string(self, security_information=DEFAULT_SECURITY_INFORMATION):
"""Return the SDDL representation of the security descriptor
:type: :class:`str`
"""
result_cstr = gdef.LPSTR()
winproxy.ConvertSecurityDescriptorToStringSecurityDescriptorA(
self,
@@ -477,6 +773,7 @@ class SecurityDescriptor(gdef.PSECURITY_DESCRIPTOR):
winproxy.LocalFree(result_cstr)
return result
# TST
# def relative(self):