mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
[22/38] Add get_perms_for_path() and get_rules_for_path() to FileRuleset
- get_rules_for_path() returns all rules matching the given path (both exact matches and AARE matches) - get_perms_for_path() returns the merged permissions for the given path and a list of paths used in the matching rules Also add tests for these two functions. Acked-by: Steve Beattie <steve@nxnw.org>
This commit is contained in:
@@ -380,7 +380,72 @@ class FileRule(BaseRule):
|
||||
class FileRuleset(BaseRuleset):
|
||||
'''Class to handle and store a collection of file rules'''
|
||||
|
||||
pass
|
||||
def get_rules_for_path(self, path, audit=False, deny=False):
|
||||
'''Get all rules matching the given path
|
||||
path can be str or AARE
|
||||
If audit is True, only return rules with the audit flag set.
|
||||
If deny is True, only return matching deny rules'''
|
||||
|
||||
matching_rules = FileRuleset()
|
||||
for rule in self.rules:
|
||||
if (rule.all_paths or rule.path.match(path)) and ((not deny) or rule.deny) and ((not audit) or rule.audit):
|
||||
matching_rules.add(rule)
|
||||
|
||||
return matching_rules
|
||||
|
||||
def get_perms_for_path(self, path, audit=False, deny=False):
|
||||
'''Get the summarized permissions of all rules matching the given path, and the list of paths involved in the calculation
|
||||
path can be str or AARE
|
||||
If audit is True, only analyze rules with the audit flag set.
|
||||
If deny is True, only analyze matching deny rules
|
||||
Returns {'allow': {'owner': set_of_perms, 'all': set_of_perms},
|
||||
'deny': {'owner': set_of_perms, 'all': set_of_perms},
|
||||
'path': involved_paths}
|
||||
Note: exec rules and exec/link target are not honored!
|
||||
'''
|
||||
# XXX do we need to honor the link target?
|
||||
|
||||
perms = {
|
||||
'allow': {'owner': set(), 'all': set() },
|
||||
'deny': {'owner': set(), 'all': set() },
|
||||
}
|
||||
all_perms = {
|
||||
'allow': {'owner': False, 'all': False },
|
||||
'deny': {'owner': False, 'all': False },
|
||||
}
|
||||
paths = set()
|
||||
|
||||
matching_rules = self.get_rules_for_path(path, audit, deny)
|
||||
|
||||
for rule in matching_rules.rules:
|
||||
allow_or_deny = 'allow'
|
||||
if rule.deny:
|
||||
allow_or_deny = 'deny'
|
||||
|
||||
owner_or_all = 'all'
|
||||
if rule.owner:
|
||||
owner_or_all = 'owner'
|
||||
|
||||
if rule.all_perms:
|
||||
all_perms[allow_or_deny][owner_or_all] = True
|
||||
elif rule.perms:
|
||||
perms[allow_or_deny][owner_or_all] = perms[allow_or_deny][owner_or_all].union(rule.perms)
|
||||
paths.add(rule.path.regex)
|
||||
|
||||
allow = {}
|
||||
deny = {}
|
||||
for who in ['all', 'owner']:
|
||||
if all_perms['allow'][who]:
|
||||
allow[who] = FileRule.ALL
|
||||
else:
|
||||
allow[who] = perms['allow'][who]
|
||||
|
||||
if all_perms['deny'][who]:
|
||||
deny[who] = FileRule.ALL
|
||||
else:
|
||||
deny[who] = perms['deny'][who]
|
||||
|
||||
return {'allow': allow, 'deny': deny, 'paths': paths}
|
||||
|
||||
|
||||
def split_perms(perm_string, deny):
|
||||
|
@@ -869,6 +869,109 @@ class FileRulesTest(AATest):
|
||||
#class FileDeleteTest(AATest):
|
||||
# pass
|
||||
|
||||
class FileGetRulesForPath(AATest):
|
||||
tests = [
|
||||
# path audit deny expected
|
||||
(('/etc/foo/dovecot.conf', False, False), ['/etc/foo/* r,', '/etc/foo/dovecot.conf rw,', '']),
|
||||
(('/etc/foo/foo.conf', False, False), ['/etc/foo/* r,', '']),
|
||||
(('/etc/foo/dovecot-database.conf.ext', False, False), ['/etc/foo/* r,', '/etc/foo/dovecot-database.conf.ext w,', '']),
|
||||
(('/etc/foo/auth.d/authfoo.conf', False, False), ['/etc/foo/{auth,conf}.d/*.conf r,','/etc/foo/{auth,conf}.d/authfoo.conf w,', '']),
|
||||
(('/etc/foo/dovecot-deny.conf', False, False), ['deny /etc/foo/dovecot-deny.conf r,', '', '/etc/foo/* r,', '']),
|
||||
(('/foo/bar', False, True ), [ ]),
|
||||
(('/etc/foo/dovecot-deny.conf', False, True ), ['deny /etc/foo/dovecot-deny.conf r,', '']),
|
||||
(('/etc/foo/foo.conf', False, True ), [ ]),
|
||||
(('/etc/foo/owner.conf', False, False), ['/etc/foo/* r,', 'owner /etc/foo/owner.conf w,', '']),
|
||||
]
|
||||
|
||||
def _run_test(self, params, expected):
|
||||
rules = [
|
||||
'/etc/foo/* r,',
|
||||
'/etc/foo/dovecot.conf rw,',
|
||||
'/etc/foo/{auth,conf}.d/*.conf r,',
|
||||
'/etc/foo/{auth,conf}.d/authfoo.conf w,',
|
||||
'/etc/foo/dovecot-database.conf.ext w,',
|
||||
'owner /etc/foo/owner.conf w,',
|
||||
'deny /etc/foo/dovecot-deny.conf r,',
|
||||
]
|
||||
|
||||
ruleset = FileRuleset()
|
||||
for rule in rules:
|
||||
ruleset.add(FileRule.parse(rule))
|
||||
|
||||
matching = ruleset.get_rules_for_path(params[0], params[1], params[2])
|
||||
self. assertEqual(matching.get_clean(), expected)
|
||||
|
||||
|
||||
class FileGetPermsForPath_1(AATest):
|
||||
tests = [
|
||||
# path audit deny expected
|
||||
(('/etc/foo/dovecot.conf', False, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot.conf' } }),
|
||||
(('/etc/foo/foo.conf', False, False), {'allow': {'all': {'r' }, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/*' } }),
|
||||
(('/etc/foo/dovecot-database.conf.ext', False, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-database.conf.ext' } }),
|
||||
(('/etc/foo/auth.d/authfoo.conf', False, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/{auth,conf}.d/*.conf', '/etc/foo/{auth,conf}.d/authfoo.conf' } }),
|
||||
(('/etc/foo/dovecot-deny.conf', False, False), {'allow': {'all': {'r' }, 'owner': set() }, 'deny': {'all': {'r' }, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-deny.conf' } }),
|
||||
(('/foo/bar', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': set() }),
|
||||
(('/etc/foo/dovecot-deny.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': {'r' }, 'owner': set() }, 'paths': {'/etc/foo/dovecot-deny.conf' } }),
|
||||
(('/etc/foo/foo.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': set() }),
|
||||
]
|
||||
|
||||
def _run_test(self, params, expected):
|
||||
rules = [
|
||||
'/etc/foo/* r,',
|
||||
'/etc/foo/dovecot.conf rw,',
|
||||
'/etc/foo/{auth,conf}.d/*.conf r,',
|
||||
'/etc/foo/{auth,conf}.d/authfoo.conf w,',
|
||||
'/etc/foo/dovecot-database.conf.ext w,',
|
||||
'deny /etc/foo/dovecot-deny.conf r,',
|
||||
'/usr/lib/dovecot/config ix,',
|
||||
]
|
||||
|
||||
ruleset = FileRuleset()
|
||||
for rule in rules:
|
||||
ruleset.add(FileRule.parse(rule))
|
||||
|
||||
perms = ruleset.get_perms_for_path(params[0], params[1], params[2])
|
||||
self. assertEqual(perms, expected)
|
||||
|
||||
class FileGetPermsForPath_2(AATest):
|
||||
tests = [
|
||||
# path audit deny expected
|
||||
(('/etc/foo/dovecot.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot.conf' } }),
|
||||
(('/etc/foo/dovecot.conf', True, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/dovecot.conf' } }),
|
||||
(('/etc/foo/foo.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*' } }),
|
||||
(('/etc/foo/dovecot-database.conf.ext', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-database.conf.ext' } }),
|
||||
(('/etc/foo/auth.d/authfoo.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/{auth,conf}.d/*.conf', '/etc/foo/{auth,conf}.d/authfoo.conf' } }),
|
||||
(('/etc/foo/auth.d/authfoo.conf', True, False), {'allow': {'all': {'w' }, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/{auth,conf}.d/authfoo.conf' } }),
|
||||
(('/etc/foo/dovecot-deny.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-deny.conf' } }),
|
||||
(('/foo/bar', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': set() }),
|
||||
(('/etc/foo/dovecot-deny.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/dovecot-deny.conf' } }),
|
||||
(('/etc/foo/foo.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': set() }),
|
||||
# (('/etc/foo/owner.conf', False, True ), {'allow': {'all': set(), 'owner': {'w'} }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/owner.conf' } }), # XXX doen't work yet
|
||||
]
|
||||
|
||||
def _run_test(self, params, expected):
|
||||
rules = [
|
||||
'/etc/foo/* r,',
|
||||
'audit /etc/foo/dovecot.conf rw,',
|
||||
'/etc/foo/{auth,conf}.d/*.conf r,',
|
||||
'audit /etc/foo/{auth,conf}.d/authfoo.conf w,',
|
||||
'/etc/foo/dovecot-database.conf.ext w,',
|
||||
'deny /etc/foo/dovecot-deny.conf r,',
|
||||
'file,',
|
||||
'owner /etc/foo/owner.conf w,',
|
||||
'deny file,',
|
||||
]
|
||||
|
||||
ruleset = FileRuleset()
|
||||
for rule in rules:
|
||||
ruleset.add(FileRule.parse(rule))
|
||||
|
||||
perms = ruleset.get_perms_for_path(params[0], params[1], params[2])
|
||||
self. assertEqual(perms, expected)
|
||||
|
||||
|
||||
|
||||
|
||||
setup_all_loops(__name__)
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
||||
|
Reference in New Issue
Block a user