mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #31906 from sbreidba/win_dacl_fixes
Win_dacl module: fix FULLCONTROL / FILE_ALL_ACCESS definition
This commit is contained in:
commit
a4b3462346
1 changed files with 77 additions and 80 deletions
|
@ -40,6 +40,12 @@ class daclConstants(object):
|
|||
'''
|
||||
dacl constants used throughout the module
|
||||
'''
|
||||
# Definition in ntsecuritycon is incorrect (does not match winnt.h). The version
|
||||
# in ntsecuritycon has the extra bits 0x200 enabled.
|
||||
# Note that you when you set this permission what you'll generally get back is it
|
||||
# ORed with 0x200 (SI_NO_ACL_PROTECT), which is what ntsecuritycon incorrectly defines.
|
||||
FILE_ALL_ACCESS = (ntsecuritycon.STANDARD_RIGHTS_REQUIRED | ntsecuritycon.SYNCHRONIZE | 0x1ff)
|
||||
|
||||
def __init__(self):
|
||||
self.hkeys_security = {
|
||||
'HKEY_LOCAL_MACHINE': 'MACHINE',
|
||||
|
@ -82,7 +88,7 @@ class daclConstants(object):
|
|||
ntsecuritycon.DELETE,
|
||||
'TEXT': 'modify'},
|
||||
'FULLCONTROL': {
|
||||
'BITS': ntsecuritycon.FILE_ALL_ACCESS,
|
||||
'BITS': daclConstants.FILE_ALL_ACCESS,
|
||||
'TEXT': 'full control'}
|
||||
}
|
||||
}
|
||||
|
@ -293,18 +299,21 @@ class daclConstants(object):
|
|||
return path
|
||||
|
||||
|
||||
class User(object):
|
||||
def _getUserSid(user):
|
||||
'''
|
||||
class object that returns a users SID
|
||||
return a state error dictionary, with 'sid' as a field if it could be returned
|
||||
if user is None, sid will also be None
|
||||
'''
|
||||
def __getattr__(self, u):
|
||||
try:
|
||||
sid = win32security.LookupAccountName('', u)[0]
|
||||
return sid
|
||||
except Exception as e:
|
||||
raise CommandExecutionError((
|
||||
'There was an error obtaining the SID of user "{0}". Error returned: {1}'
|
||||
).format(u, e))
|
||||
ret = {}
|
||||
try:
|
||||
sid = win32security.LookupAccountName('', user)[0] if user else None
|
||||
ret['result'] = True
|
||||
ret['sid'] = sid
|
||||
except Exception as e:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Unable to obtain the security identifier for {0}. The exception was {1}.'.format(
|
||||
user, e)
|
||||
return ret
|
||||
|
||||
|
||||
def __virtual__():
|
||||
|
@ -329,13 +338,16 @@ def _get_dacl(path, objectType):
|
|||
return dacl
|
||||
|
||||
|
||||
def get(path, objectType):
|
||||
def get(path, objectType, user=None):
|
||||
'''
|
||||
get the acl of an object
|
||||
Get the acl of an object. Will filter by user if one is provided.
|
||||
'''
|
||||
ret = {'Path': path,
|
||||
'ACLs': []}
|
||||
|
||||
sidRet = _getUserSid(user)
|
||||
if not sidRet['result']:
|
||||
return sidRet
|
||||
if path and objectType:
|
||||
dc = daclConstants()
|
||||
objectTypeBit = dc.getObjectTypeBit(objectType)
|
||||
|
@ -344,7 +356,8 @@ def get(path, objectType):
|
|||
if tdacl:
|
||||
for counter in range(0, tdacl.GetAceCount()):
|
||||
tAce = tdacl.GetAce(counter)
|
||||
ret['ACLs'].append(_ace_to_text(tAce, objectTypeBit))
|
||||
if not sidRet['sid'] or (tAce[2] == sidRet['sid']):
|
||||
ret['ACLs'].append(_ace_to_text(tAce, objectTypeBit))
|
||||
return ret
|
||||
|
||||
|
||||
|
@ -377,13 +390,14 @@ def add_ace(path, objectType, user, permission, acetype, propagation):
|
|||
dc = daclConstants()
|
||||
objectTypeBit = dc.getObjectTypeBit(objectType)
|
||||
path = dc.processPath(path, objectTypeBit)
|
||||
u = User()
|
||||
user = user.strip()
|
||||
permission = permission.strip().upper()
|
||||
acetype = acetype.strip().upper()
|
||||
propagation = propagation.strip().upper()
|
||||
|
||||
thisSid = getattr(u, user)
|
||||
sidRet = _getUserSid(user)
|
||||
if not sidRet['result']:
|
||||
return sidRet
|
||||
permissionbit = dc.getPermissionBit(objectTypeBit, permission)
|
||||
acetypebit = dc.getAceTypeBit(acetype)
|
||||
propagationbit = dc.getPropagationBit(objectTypeBit, propagation)
|
||||
|
@ -393,9 +407,9 @@ def add_ace(path, objectType, user, permission, acetype, propagation):
|
|||
acesAdded = []
|
||||
try:
|
||||
if acetypebit == 0:
|
||||
dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, propagationbit, permissionbit, thisSid)
|
||||
dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, propagationbit, permissionbit, sidRet['sid'])
|
||||
elif acetypebit == 1:
|
||||
dacl.AddAccessDeniedAceEx(win32security.ACL_REVISION, propagationbit, permissionbit, thisSid)
|
||||
dacl.AddAccessDeniedAceEx(win32security.ACL_REVISION, propagationbit, permissionbit, sidRet['sid'])
|
||||
win32security.SetNamedSecurityInfo(
|
||||
path, objectTypeBit, win32security.DACL_SECURITY_INFORMATION,
|
||||
None, None, dacl, None)
|
||||
|
@ -419,7 +433,7 @@ def add_ace(path, objectType, user, permission, acetype, propagation):
|
|||
return ret
|
||||
|
||||
|
||||
def rm_ace(path, objectType, user, permission, acetype, propagation):
|
||||
def rm_ace(path, objectType, user, permission=None, acetype=None, propagation=None):
|
||||
r'''
|
||||
remove an ace to an object
|
||||
|
||||
|
@ -429,7 +443,7 @@ def rm_ace(path, objectType, user, permission, acetype, propagation):
|
|||
acetypes: either allow/deny for each user/permission (ALLOW, DENY)
|
||||
propagation: how the ACE applies to children for Registry Keys and Directories(KEY, KEY&SUBKEYS, SUBKEYS)
|
||||
|
||||
***The entire ACE must match to be removed***
|
||||
If any of the optional parameters are ommitted (or set to None) they act as wildcards.
|
||||
|
||||
CLI Example:
|
||||
|
||||
|
@ -442,50 +456,38 @@ def rm_ace(path, objectType, user, permission, acetype, propagation):
|
|||
'changes': {},
|
||||
'comment': ''}
|
||||
|
||||
if (path and user and
|
||||
permission and acetype
|
||||
and propagation):
|
||||
if (path and user):
|
||||
dc = daclConstants()
|
||||
if objectType.upper() == "FILE":
|
||||
if propagation and objectType.upper() == "FILE":
|
||||
propagation = "FILE"
|
||||
objectTypeBit = dc.getObjectTypeBit(objectType)
|
||||
path = dc.processPath(path, objectTypeBit)
|
||||
|
||||
u = User()
|
||||
user = user.strip()
|
||||
permission = permission.strip().upper()
|
||||
acetype = acetype.strip().upper()
|
||||
propagation = propagation.strip().upper()
|
||||
permission = permission.strip().upper() if permission else None
|
||||
acetype = acetype.strip().upper() if acetype else None
|
||||
propagation = propagation.strip().upper() if propagation else None
|
||||
|
||||
if check_ace(path, objectType, user, permission, acetype, propagation, True)['Exists']:
|
||||
thisSid = getattr(u, user)
|
||||
permissionbit = dc.getPermissionBit(objectTypeBit, permission)
|
||||
acetypebit = dc.getAceTypeBit(acetype)
|
||||
propagationbit = dc.getPropagationBit(objectTypeBit, propagation)
|
||||
sidRet = _getUserSid(user)
|
||||
if not sidRet['result']:
|
||||
return sidRet
|
||||
permissionbit = dc.getPermissionBit(objectTypeBit, permission) if permission else None
|
||||
acetypebit = dc.getAceTypeBit(acetype) if acetype else None
|
||||
propagationbit = dc.getPropagationBit(objectTypeBit, propagation) if propagation else None
|
||||
dacl = _get_dacl(path, objectTypeBit)
|
||||
counter = 0
|
||||
acesRemoved = []
|
||||
if objectTypeBit == win32security.SE_FILE_OBJECT:
|
||||
if check_inheritance(path, objectType)['Inheritance']:
|
||||
if permission == 'FULLCONTROL':
|
||||
# if inhertiance is enabled on an SE_FILE_OBJECT, then the SI_NO_ACL_PROTECT
|
||||
# gets unset on FullControl which greys out the include inheritable permission
|
||||
# checkbox on the advanced security settings gui page
|
||||
permissionbit = permissionbit ^ ntsecuritycon.SI_NO_ACL_PROTECT
|
||||
while counter < dacl.GetAceCount():
|
||||
tAce = dacl.GetAce(counter)
|
||||
if (tAce[0][1] & win32security.INHERITED_ACE) != win32security.INHERITED_ACE:
|
||||
if tAce[2] == thisSid:
|
||||
if tAce[0][0] == acetypebit:
|
||||
if (tAce[0][1] & propagationbit) == propagationbit:
|
||||
if tAce[1] == permissionbit:
|
||||
if tAce[2] == sidRet['sid']:
|
||||
if not acetypebit or tAce[0][0] == acetypebit:
|
||||
if not propagationbit or ((tAce[0][1] & propagationbit) == propagationbit):
|
||||
if not permissionbit or tAce[1] == permissionbit:
|
||||
dacl.DeleteAce(counter)
|
||||
counter = counter - 1
|
||||
acesRemoved.append((
|
||||
'{0} {1} {2} on {3}'
|
||||
).format(user, dc.getAceTypeText(acetype),
|
||||
dc.getPermissionText(objectTypeBit, permission),
|
||||
dc.getPropagationText(objectTypeBit, propagation)))
|
||||
acesRemoved.append(_ace_to_text(tAce, objectTypeBit))
|
||||
|
||||
counter = counter + 1
|
||||
if acesRemoved:
|
||||
|
@ -530,11 +532,6 @@ def _ace_to_text(ace, objectType):
|
|||
if dc.rights[objectType][x]['BITS'] == tPerm:
|
||||
tPerm = dc.rights[objectType][x]['TEXT']
|
||||
break
|
||||
else:
|
||||
if objectType == win32security.SE_FILE_OBJECT:
|
||||
if (tPerm ^ ntsecuritycon.FILE_ALL_ACCESS) == ntsecuritycon.SI_NO_ACL_PROTECT:
|
||||
tPerm = 'full control'
|
||||
break
|
||||
if (tProps & win32security.INHERITED_ACE) == win32security.INHERITED_ACE:
|
||||
tInherited = '[Inherited]'
|
||||
tProps = (tProps ^ win32security.INHERITED_ACE)
|
||||
|
@ -633,18 +630,23 @@ def disable_inheritance(path, objectType, copy=True):
|
|||
return _set_dacl_inheritance(path, objectType, False, copy, None)
|
||||
|
||||
|
||||
def check_inheritance(path, objectType):
|
||||
def check_inheritance(path, objectType, user=None):
|
||||
'''
|
||||
check a specified path to verify if inheritance is enabled
|
||||
returns 'Inheritance' of True/False
|
||||
|
||||
hkey: HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, etc
|
||||
path: path of the registry key to check
|
||||
path: path of the registry key or file system object to check
|
||||
user: if provided, will consider only the ACEs for that user
|
||||
'''
|
||||
|
||||
ret = {'result': False,
|
||||
'Inheritance': False,
|
||||
'comment': ''}
|
||||
|
||||
sidRet = _getUserSid(user)
|
||||
if not sidRet['result']:
|
||||
return sidRet
|
||||
|
||||
dc = daclConstants()
|
||||
objectType = dc.getObjectTypeBit(objectType)
|
||||
path = dc.processPath(path, objectType)
|
||||
|
@ -660,12 +662,14 @@ def check_inheritance(path, objectType):
|
|||
for counter in range(0, dacls.GetAceCount()):
|
||||
ace = dacls.GetAce(counter)
|
||||
if (ace[0][1] & win32security.INHERITED_ACE) == win32security.INHERITED_ACE:
|
||||
ret['Inheritance'] = True
|
||||
if not sidRet['sid'] or ace[2] == sidRet['sid']:
|
||||
ret['Inheritance'] = True
|
||||
return ret
|
||||
ret['result'] = True
|
||||
return ret
|
||||
|
||||
|
||||
def check_ace(path, objectType, user=None, permission=None, acetype=None, propagation=None, exactPermissionMatch=False):
|
||||
def check_ace(path, objectType, user, permission=None, acetype=None, propagation=None, exactPermissionMatch=False):
|
||||
'''
|
||||
checks a path to verify the ACE (access control entry) specified exists
|
||||
returns 'Exists' true if the ACE exists, false if it does not
|
||||
|
@ -686,36 +690,29 @@ def check_ace(path, objectType, user=None, permission=None, acetype=None, propag
|
|||
objectTypeBit = dc.getObjectTypeBit(objectType)
|
||||
path = dc.processPath(path, objectTypeBit)
|
||||
|
||||
permission = permission.upper()
|
||||
acetype = acetype.upper()
|
||||
propagation = propagation.upper()
|
||||
permission = permission.upper() if permission else None
|
||||
acetype = acetype.upper() if permission else None
|
||||
propagation = propagation.upper() if propagation else None
|
||||
|
||||
permissionbit = dc.getPermissionBit(objectTypeBit, permission)
|
||||
acetypebit = dc.getAceTypeBit(acetype)
|
||||
propagationbit = dc.getPropagationBit(objectTypeBit, propagation)
|
||||
permissionbit = dc.getPermissionBit(objectTypeBit, permission) if permission else None
|
||||
acetypebit = dc.getAceTypeBit(acetype) if acetype else None
|
||||
propagationbit = dc.getPropagationBit(objectTypeBit, propagation) if propagation else None
|
||||
|
||||
try:
|
||||
userSid = win32security.LookupAccountName('', user)[0]
|
||||
except Exception as e:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Unable to obtain the security identifier for {0}. The exception was {1}.'.format(user, e)
|
||||
return ret
|
||||
sidRet = _getUserSid(user)
|
||||
if not sidRet['result']:
|
||||
return sidRet
|
||||
|
||||
dacls = _get_dacl(path, objectTypeBit)
|
||||
ret['result'] = True
|
||||
if dacls:
|
||||
if objectTypeBit == win32security.SE_FILE_OBJECT:
|
||||
if check_inheritance(path, objectType)['Inheritance']:
|
||||
if permission == 'FULLCONTROL':
|
||||
# if inhertiance is enabled on an SE_FILE_OBJECT, then the SI_NO_ACL_PROTECT
|
||||
# gets unset on FullControl which greys out the include inheritable permission
|
||||
# checkbox on the advanced security settings gui page
|
||||
permissionbit = permissionbit ^ ntsecuritycon.SI_NO_ACL_PROTECT
|
||||
for counter in range(0, dacls.GetAceCount()):
|
||||
ace = dacls.GetAce(counter)
|
||||
if ace[2] == userSid:
|
||||
if ace[0][0] == acetypebit:
|
||||
if (ace[0][1] & propagationbit) == propagationbit:
|
||||
if ace[2] == sidRet['sid']:
|
||||
if not acetypebit or ace[0][0] == acetypebit:
|
||||
if not propagationbit or (ace[0][1] & propagationbit) == propagationbit:
|
||||
if not permissionbit:
|
||||
ret['Exists'] = True
|
||||
return ret
|
||||
if exactPermissionMatch:
|
||||
if ace[1] == permissionbit:
|
||||
ret['Exists'] = True
|
||||
|
|
Loading…
Add table
Reference in a new issue