256 lines
8.8 KiB
Python
256 lines
8.8 KiB
Python
|
import os
|
||
|
|
||
|
import ntsecuritycon
|
||
|
import pythoncom
|
||
|
import win32api
|
||
|
import win32com.server.policy
|
||
|
import win32con
|
||
|
import win32security
|
||
|
from ntsecuritycon import (
|
||
|
CONTAINER_INHERIT_ACE,
|
||
|
FILE_ALL_ACCESS,
|
||
|
FILE_APPEND_DATA,
|
||
|
FILE_GENERIC_EXECUTE,
|
||
|
FILE_GENERIC_READ,
|
||
|
FILE_GENERIC_WRITE,
|
||
|
FILE_READ_ATTRIBUTES,
|
||
|
FILE_READ_DATA,
|
||
|
FILE_READ_EA,
|
||
|
FILE_WRITE_ATTRIBUTES,
|
||
|
FILE_WRITE_DATA,
|
||
|
FILE_WRITE_EA,
|
||
|
INHERIT_ONLY_ACE,
|
||
|
OBJECT_INHERIT_ACE,
|
||
|
PSPCB_SI_INITDIALOG,
|
||
|
READ_CONTROL,
|
||
|
SI_ACCESS_CONTAINER,
|
||
|
SI_ACCESS_GENERAL,
|
||
|
SI_ACCESS_PROPERTY,
|
||
|
SI_ACCESS_SPECIFIC,
|
||
|
SI_ADVANCED,
|
||
|
SI_CONTAINER,
|
||
|
SI_EDIT_ALL,
|
||
|
SI_EDIT_AUDITS,
|
||
|
SI_EDIT_PROPERTIES,
|
||
|
SI_PAGE_ADVPERM,
|
||
|
SI_PAGE_AUDIT,
|
||
|
SI_PAGE_OWNER,
|
||
|
SI_PAGE_PERM,
|
||
|
SI_PAGE_TITLE,
|
||
|
SI_RESET,
|
||
|
STANDARD_RIGHTS_EXECUTE,
|
||
|
STANDARD_RIGHTS_READ,
|
||
|
STANDARD_RIGHTS_WRITE,
|
||
|
SYNCHRONIZE,
|
||
|
WRITE_DAC,
|
||
|
WRITE_OWNER,
|
||
|
)
|
||
|
from pythoncom import IID_NULL
|
||
|
from win32com.authorization import authorization
|
||
|
from win32com.shell.shellcon import ( # # Msg parameter to PropertySheetPageCallback
|
||
|
PSPCB_CREATE,
|
||
|
PSPCB_RELEASE,
|
||
|
)
|
||
|
from win32security import CONTAINER_INHERIT_ACE, INHERIT_ONLY_ACE, OBJECT_INHERIT_ACE
|
||
|
|
||
|
|
||
|
class SecurityInformation(win32com.server.policy.DesignatedWrapPolicy):
|
||
|
_com_interfaces_ = [authorization.IID_ISecurityInformation]
|
||
|
_public_methods_ = [
|
||
|
"GetObjectInformation",
|
||
|
"GetSecurity",
|
||
|
"SetSecurity",
|
||
|
"GetAccessRights",
|
||
|
"GetInheritTypes",
|
||
|
"MapGeneric",
|
||
|
"PropertySheetPageCallback",
|
||
|
]
|
||
|
|
||
|
def __init__(self, FileName):
|
||
|
self.FileName = FileName
|
||
|
self._wrap_(self)
|
||
|
|
||
|
def GetObjectInformation(self):
|
||
|
"""Identifies object whose security will be modified, and determines options available
|
||
|
to the end user"""
|
||
|
flags = SI_ADVANCED | SI_EDIT_ALL | SI_PAGE_TITLE | SI_RESET
|
||
|
if os.path.isdir(self.FileName):
|
||
|
flags |= SI_CONTAINER
|
||
|
hinstance = 0 ## handle to module containing string resources
|
||
|
servername = "" ## name of authenticating server if not local machine
|
||
|
objectname = os.path.split(self.FileName)[1]
|
||
|
pagetitle = "Python ACL Editor"
|
||
|
if os.path.isdir(self.FileName):
|
||
|
pagetitle += " (dir)"
|
||
|
else:
|
||
|
pagetitle += " (file)"
|
||
|
objecttype = IID_NULL
|
||
|
return flags, hinstance, servername, objectname, pagetitle, objecttype
|
||
|
|
||
|
def GetSecurity(self, requestedinfo, bdefault):
|
||
|
"""Requests the existing permissions for object"""
|
||
|
if bdefault:
|
||
|
## This is invoked if the 'Default' button is pressed (only present if SI_RESET is passed
|
||
|
## with the flags in GetObjectInfo). Passing an empty SD with a NULL Dacl
|
||
|
## should cause inherited ACL from parent dir or default dacl from user's token to be used
|
||
|
return win32security.SECURITY_DESCRIPTOR()
|
||
|
else:
|
||
|
## GetFileSecurity sometimes fails to return flags indicating that an ACE is inherited
|
||
|
return win32security.GetNamedSecurityInfo(
|
||
|
self.FileName, win32security.SE_FILE_OBJECT, requestedinfo
|
||
|
)
|
||
|
|
||
|
def SetSecurity(self, requestedinfo, sd):
|
||
|
"""Applies permissions to the object"""
|
||
|
owner = sd.GetSecurityDescriptorOwner()
|
||
|
group = sd.GetSecurityDescriptorGroup()
|
||
|
dacl = sd.GetSecurityDescriptorDacl()
|
||
|
sacl = sd.GetSecurityDescriptorSacl()
|
||
|
win32security.SetNamedSecurityInfo(
|
||
|
self.FileName,
|
||
|
win32security.SE_FILE_OBJECT,
|
||
|
requestedinfo,
|
||
|
owner,
|
||
|
group,
|
||
|
dacl,
|
||
|
sacl,
|
||
|
)
|
||
|
## should also handle recursive operations here
|
||
|
|
||
|
def GetAccessRights(self, objecttype, flags):
|
||
|
"""Returns a tuple of (AccessRights, DefaultAccess), where AccessRights is a sequence of tuples representing
|
||
|
SI_ACCESS structs, containing (guid, access mask, Name, flags). DefaultAccess indicates which of the
|
||
|
AccessRights will be used initially when a new ACE is added (zero based).
|
||
|
Flags can contain SI_ACCESS_SPECIFIC,SI_ACCESS_GENERAL,SI_ACCESS_CONTAINER,SI_ACCESS_PROPERTY,
|
||
|
CONTAINER_INHERIT_ACE,INHERIT_ONLY_ACE,OBJECT_INHERIT_ACE
|
||
|
"""
|
||
|
## input flags: SI_ADVANCED,SI_EDIT_AUDITS,SI_EDIT_PROPERTIES indicating which property sheet is requesting the rights
|
||
|
if (objecttype is not None) and (objecttype != IID_NULL):
|
||
|
## Should not be true for file objects. Usually only used with DS objects that support security for
|
||
|
## their properties
|
||
|
raise NotImplementedError("Object type is not supported")
|
||
|
|
||
|
if os.path.isdir(self.FileName):
|
||
|
file_append_data_desc = "Create subfolders"
|
||
|
file_write_data_desc = "Create Files"
|
||
|
else:
|
||
|
file_append_data_desc = "Append data"
|
||
|
file_write_data_desc = "Write data"
|
||
|
|
||
|
accessrights = [
|
||
|
(
|
||
|
IID_NULL,
|
||
|
FILE_GENERIC_READ,
|
||
|
"Generic read",
|
||
|
SI_ACCESS_GENERAL
|
||
|
| SI_ACCESS_SPECIFIC
|
||
|
| OBJECT_INHERIT_ACE
|
||
|
| CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
FILE_GENERIC_WRITE,
|
||
|
"Generic write",
|
||
|
SI_ACCESS_GENERAL
|
||
|
| SI_ACCESS_SPECIFIC
|
||
|
| OBJECT_INHERIT_ACE
|
||
|
| CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
win32con.DELETE,
|
||
|
"Delete",
|
||
|
SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
WRITE_OWNER,
|
||
|
"Change owner",
|
||
|
SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
READ_CONTROL,
|
||
|
"Read Permissions",
|
||
|
SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
WRITE_DAC,
|
||
|
"Change permissions",
|
||
|
SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
FILE_APPEND_DATA,
|
||
|
file_append_data_desc,
|
||
|
SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
FILE_WRITE_DATA,
|
||
|
file_write_data_desc,
|
||
|
SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
|
||
|
),
|
||
|
]
|
||
|
return (accessrights, 0)
|
||
|
|
||
|
def MapGeneric(self, guid, aceflags, mask):
|
||
|
"""Converts generic access rights to specific rights. This implementation uses standard file system rights,
|
||
|
but you can map them any way that suits your application.
|
||
|
"""
|
||
|
return win32security.MapGenericMask(
|
||
|
mask,
|
||
|
(
|
||
|
FILE_GENERIC_READ,
|
||
|
FILE_GENERIC_WRITE,
|
||
|
FILE_GENERIC_EXECUTE,
|
||
|
FILE_ALL_ACCESS,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
def GetInheritTypes(self):
|
||
|
"""Specifies which types of ACE inheritance are supported.
|
||
|
Returns a sequence of tuples representing SI_INHERIT_TYPE structs, containing
|
||
|
(object type guid, inheritance flags, display name). Guid is usually only used with
|
||
|
Directory Service objects.
|
||
|
"""
|
||
|
return (
|
||
|
(IID_NULL, 0, "Only current object"),
|
||
|
(IID_NULL, OBJECT_INHERIT_ACE, "Files inherit permissions"),
|
||
|
(IID_NULL, CONTAINER_INHERIT_ACE, "Sub Folders inherit permissions"),
|
||
|
(
|
||
|
IID_NULL,
|
||
|
CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE,
|
||
|
"Files and subfolders",
|
||
|
),
|
||
|
)
|
||
|
|
||
|
def PropertySheetPageCallback(self, hwnd, msg, pagetype):
|
||
|
"""Invoked each time a property sheet page is created or destroyed."""
|
||
|
## page types from SI_PAGE_TYPE enum: SI_PAGE_PERM SI_PAGE_ADVPERM SI_PAGE_AUDIT SI_PAGE_OWNER
|
||
|
## msg: PSPCB_CREATE, PSPCB_RELEASE, PSPCB_SI_INITDIALOG
|
||
|
return None
|
||
|
|
||
|
def EditSecurity(self, owner_hwnd=0):
|
||
|
"""Creates an ACL editor dialog based on parameters returned by interface methods"""
|
||
|
isi = pythoncom.WrapObject(
|
||
|
self, authorization.IID_ISecurityInformation, pythoncom.IID_IUnknown
|
||
|
)
|
||
|
authorization.EditSecurity(owner_hwnd, isi)
|
||
|
|
||
|
|
||
|
## folder permissions
|
||
|
temp_dir = win32api.GetTempPath()
|
||
|
dir_name = win32api.GetTempFileName(temp_dir, "isi")[0]
|
||
|
print(dir_name)
|
||
|
os.remove(dir_name)
|
||
|
os.mkdir(dir_name)
|
||
|
si = SecurityInformation(dir_name)
|
||
|
si.EditSecurity()
|
||
|
|
||
|
## file permissions
|
||
|
fname = win32api.GetTempFileName(dir_name, "isi")[0]
|
||
|
si = SecurityInformation(fname)
|
||
|
si.EditSecurity()
|