mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Only ran sed -i s/ *// in ./apparmor/*.py , ./Tools/aa* and ./Testing/*.py no other changes, should ignore this commit unless it broke something
This commit is contained in:
parent
86e7c22196
commit
4debd1ea79
19 changed files with 821 additions and 823 deletions
|
@ -6,9 +6,9 @@ import apparmor.aa
|
|||
import apparmor.logparser
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
|
||||
def setUp(self):
|
||||
self.MODE_TEST = {'x': apparmor.aamode.AA_MAY_EXEC,
|
||||
self.MODE_TEST = {'x': apparmor.aamode.AA_MAY_EXEC,
|
||||
'w': apparmor.aamode.AA_MAY_WRITE,
|
||||
'r': apparmor.aamode.AA_MAY_READ,
|
||||
'a': apparmor.aamode.AA_MAY_APPEND,
|
||||
|
@ -26,7 +26,7 @@ class Test(unittest.TestCase):
|
|||
|
||||
def test_loadinclude(self):
|
||||
apparmor.aa.loadincludes()
|
||||
|
||||
|
||||
def test_path_globs(self):
|
||||
globs = {
|
||||
'/foo/': '/*/',
|
||||
|
@ -47,15 +47,15 @@ class Test(unittest.TestCase):
|
|||
'/usr/foo/**/*': '/usr/foo/**',
|
||||
'/usr/foo/*/bar': '/usr/foo/*/*',
|
||||
'/usr/bin/foo*bar': '/usr/bin/*',
|
||||
'/usr/bin/*foo*': '/usr/bin/*',
|
||||
'/usr/bin/*foo*': '/usr/bin/*',
|
||||
'/usr/foo/*/*': '/usr/foo/**',
|
||||
'/usr/foo/*/**': '/usr/foo/**',
|
||||
'/**': '/**',
|
||||
'/**/': '/**/'
|
||||
'/**/': '/**/'
|
||||
}
|
||||
for path in globs.keys():
|
||||
self.assertEqual(apparmor.aa.glob_path(path), globs[path], 'Unexpected glob generated for path: %s'%path)
|
||||
|
||||
|
||||
def test_path_withext_globs(self):
|
||||
globs = {
|
||||
'/foo/bar': '/foo/bar',
|
||||
|
@ -70,11 +70,11 @@ class Test(unittest.TestCase):
|
|||
'/usr/*foo*.bar': '/usr/*.bar',
|
||||
'/usr/**foo.bar': '/usr/**.bar',
|
||||
'/usr/*foo.bar': '/usr/*.bar',
|
||||
'/usr/foo.b*': '/usr/*.b*'
|
||||
'/usr/foo.b*': '/usr/*.b*'
|
||||
}
|
||||
for path in globs.keys():
|
||||
self.assertEqual(apparmor.aa.glob_path_withext(path), globs[path], 'Unexpected glob generated for path: %s'%path)
|
||||
|
||||
|
||||
def test_parse_event(self):
|
||||
parser = apparmor.logparser.ReadLog('', '', '', '', '')
|
||||
event = 'type=AVC msg=audit(1345027352.096:499): apparmor="ALLOWED" operation="rename_dest" parent=6974 profile="/usr/sbin/httpd2-prefork//vhost_foo" name=2F686F6D652F7777772F666F6F2E6261722E696E2F68747470646F63732F61707061726D6F722F696D616765732F746573742F696D61676520312E6A7067 pid=20143 comm="httpd2-prefork" requested_mask="wc" denied_mask="wc" fsuid=30 ouid=30'
|
||||
|
@ -84,11 +84,11 @@ class Test(unittest.TestCase):
|
|||
self.assertEqual(parsed_event['aamode'], 'PERMITTING')
|
||||
self.assertEqual(parsed_event['request_mask'], set(['w', 'a', '::w', '::a']))
|
||||
#print(parsed_event)
|
||||
|
||||
|
||||
#event = 'type=AVC msg=audit(1322614912.304:857): apparmor="ALLOWED" operation="getattr" parent=16001 profile=74657374207370616365 name=74657374207370616365 pid=17011 comm="bash" requested_mask="r" denied_mask="r" fsuid=0 ouid=0'
|
||||
#parsed_event = apparmor.aa.parse_event(event)
|
||||
#print(parsed_event)
|
||||
|
||||
|
||||
event = 'type=AVC msg=audit(1322614918.292:4376): apparmor="ALLOWED" operation="file_perm" parent=16001 profile=666F6F20626172 name="/home/foo/.bash_history" pid=17011 comm="bash" requested_mask="rw" denied_mask="rw" fsuid=0 ouid=1000'
|
||||
parsed_event = parser.parse_event(event)
|
||||
self.assertEqual(parsed_event['name'], '/home/foo/.bash_history', 'Incorrectly parsed/decoded name')
|
||||
|
@ -96,19 +96,19 @@ class Test(unittest.TestCase):
|
|||
self.assertEqual(parsed_event['aamode'], 'PERMITTING')
|
||||
self.assertEqual(parsed_event['request_mask'], set(['r', 'w', 'a','::r' , '::w', '::a']))
|
||||
#print(parsed_event)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_modes_to_string(self):
|
||||
|
||||
|
||||
|
||||
|
||||
for string in self.MODE_TEST.keys():
|
||||
mode = self.MODE_TEST[string]
|
||||
self.assertEqual(apparmor.aamode.mode_to_str(mode), string, 'mode is %s and string is %s'%(mode, string))
|
||||
|
||||
|
||||
def test_string_to_modes(self):
|
||||
|
||||
#self.assertEqual(apparmor.aa.str_to_mode('wc'), 32270)
|
||||
MODE_TEST = {'x': apparmor.aamode.AA_MAY_EXEC,
|
||||
MODE_TEST = {'x': apparmor.aamode.AA_MAY_EXEC,
|
||||
'w': apparmor.aamode.AA_MAY_WRITE,
|
||||
'r': apparmor.aamode.AA_MAY_READ,
|
||||
'a': apparmor.aamode.AA_MAY_APPEND,
|
||||
|
@ -123,11 +123,11 @@ class Test(unittest.TestCase):
|
|||
'c': apparmor.aamode.AA_EXEC_CHILD | apparmor.aamode.AA_EXEC_UNSAFE, # Child + Unsafe
|
||||
'C': apparmor.aamode.AA_EXEC_CHILD,
|
||||
}
|
||||
|
||||
|
||||
#while MODE_TEST:
|
||||
# string,mode = MODE_TEST.popitem()
|
||||
# self.assertEqual(apparmor.aamode.str_to_mode(string), mode)
|
||||
|
||||
|
||||
#self.assertEqual(apparmor.aa.str_to_mode('C'), 2048)
|
||||
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ class Test(unittest.TestCase):
|
|||
parsed_regex = re.compile(apparmor.common.convert_regexp(regex))
|
||||
for regex_testcase in regex_tests.options(regex):
|
||||
self.assertEqual(bool(parsed_regex.search(regex_testcase)), eval(regex_tests[regex][regex_testcase]), 'Incorrectly Parsed regex: %s' %regex)
|
||||
|
||||
|
||||
#def test_readkey(self):
|
||||
# print("Please press the Y button on the keyboard.")
|
||||
# self.assertEqual(apparmor.common.readkey().lower(), 'y', 'Error reading key from shell!')
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
#import sys;sys.argv = ['', 'Test.test_RegexParser']
|
||||
|
|
|
@ -14,11 +14,11 @@ class Test(unittest.TestCase):
|
|||
logprof_sections = ['settings', 'repository', 'qualifiers', 'required_hats', 'defaulthat', 'globs']
|
||||
logprof_sections_options = ['profiledir', 'inactive_profiledir', 'logfiles', 'parser', 'ldd', 'logger', 'default_owner_prompt', 'custom_includes']
|
||||
logprof_settings_parser = '/sbin/apparmor_parser /sbin/subdomain_parser'
|
||||
|
||||
|
||||
self.assertEqual(conf.sections(), logprof_sections)
|
||||
self.assertEqual(conf.options('settings'), logprof_sections_options)
|
||||
self.assertEqual(conf['settings']['parser'], logprof_settings_parser)
|
||||
|
||||
|
||||
def test_ShellConfig(self):
|
||||
shell_config = config.Config('shell')
|
||||
shell_config.CONF_DIR = '.'
|
||||
|
@ -26,12 +26,12 @@ class Test(unittest.TestCase):
|
|||
easyprof_sections = ['POLICYGROUPS_DIR', 'TEMPLATES_DIR']
|
||||
easyprof_Policygroup = '/usr/share/apparmor/easyprof/policygroups'
|
||||
easyprof_Templates = '/usr/share/apparmor/easyprof/templates'
|
||||
|
||||
|
||||
self.assertEqual(sorted(list(conf[''].keys())), sorted(easyprof_sections))
|
||||
self.assertEqual(conf['']['POLICYGROUPS_DIR'], easyprof_Policygroup)
|
||||
self.assertEqual(conf['']['TEMPLATES_DIR'], easyprof_Templates)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -18,81 +18,81 @@ if sys.version_info >= (3,0):
|
|||
python_interpreter = 'python3'
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
|
||||
def test_audit(self):
|
||||
#Set ntpd profile to audit mode and check if it was correctly set
|
||||
str(subprocess.check_output('%s ./../Tools/aa-audit -d ./profiles %s'%(python_interpreter, test_path), shell=True))
|
||||
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), 'audit', 'Audit flag could not be set in profile %s'%local_profilename)
|
||||
|
||||
|
||||
#Remove audit mode from ntpd profile and check if it was correctly removed
|
||||
subprocess.check_output('%s ./../Tools/aa-audit -d ./profiles -r %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), None, 'Complain flag could not be removed in profile %s'%local_profilename)
|
||||
|
||||
|
||||
|
||||
def test_complain(self):
|
||||
#Set ntpd profile to complain mode and check if it was correctly set
|
||||
subprocess.check_output('%s ./../Tools/aa-complain -d ./profiles %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/force-complain/%s'%os.path.basename(local_profilename)), True, 'Failed to create a symlink for %s in force-complain'%local_profilename)
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), 'complain', 'Complain flag could not be set in profile %s'%local_profilename)
|
||||
|
||||
|
||||
#Set ntpd profile to enforce mode and check if it was correctly set
|
||||
subprocess.check_output('%s ./../Tools/aa-complain -d ./profiles -r %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/force-complain/%s'%os.path.basename(local_profilename)), False, 'Failed to remove symlink for %s from force-complain'%local_profilename)
|
||||
self.assertEqual(os.path.islink('./profiles/disable/%s'%os.path.basename(local_profilename)), False, 'Failed to remove symlink for %s from disable'%local_profilename)
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), None, 'Complain flag could not be removed in profile %s'%local_profilename)
|
||||
|
||||
|
||||
# Set audit flag and then complain flag in a profile
|
||||
subprocess.check_output('%s ./../Tools/aa-audit -d ./profiles %s'%(python_interpreter, test_path), shell=True)
|
||||
subprocess.check_output('%s ./../Tools/aa-complain -d ./profiles %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/force-complain/%s'%os.path.basename(local_profilename)), True, 'Failed to create a symlink for %s in force-complain'%local_profilename)
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), 'audit,complain', 'Complain flag could not be set in profile %s'%local_profilename)
|
||||
|
||||
|
||||
#Remove complain flag first i.e. set to enforce mode
|
||||
subprocess.check_output('%s ./../Tools/aa-complain -d ./profiles -r %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/force-complain/%s'%os.path.basename(local_profilename)), False, 'Failed to remove symlink for %s from force-complain'%local_profilename)
|
||||
self.assertEqual(os.path.islink('./profiles/disable/%s'%os.path.basename(local_profilename)), False, 'Failed to remove symlink for %s from disable'%local_profilename)
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), 'audit', 'Complain flag could not be removed in profile %s'%local_profilename)
|
||||
|
||||
|
||||
#Remove audit flag
|
||||
subprocess.check_output('%s ./../Tools/aa-audit -d ./profiles -r %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
|
||||
def test_enforce(self):
|
||||
#Set ntpd profile to complain mode and check if it was correctly set
|
||||
subprocess.check_output('%s ./../Tools/aa-enforce -d ./profiles -r %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/force-complain/%s'%os.path.basename(local_profilename)), True, 'Failed to create a symlink for %s in force-complain'%local_profilename)
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), 'complain', 'Complain flag could not be set in profile %s'%local_profilename)
|
||||
|
||||
|
||||
|
||||
|
||||
#Set ntpd profile to enforce mode and check if it was correctly set
|
||||
subprocess.check_output('%s ./../Tools/aa-enforce -d ./profiles %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/force-complain/%s'%os.path.basename(local_profilename)), False, 'Failed to remove symlink for %s from force-complain'%local_profilename)
|
||||
self.assertEqual(os.path.islink('./profiles/disable/%s'%os.path.basename(local_profilename)), False, 'Failed to remove symlink for %s from disable'%local_profilename)
|
||||
self.assertEqual(apparmor.get_profile_flags(local_profilename, test_path), None, 'Complain flag could not be removed in profile %s'%local_profilename)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_disable(self):
|
||||
#Disable the ntpd profile and check if it was correctly disabled
|
||||
subprocess.check_output('%s ./../Tools/aa-disable -d ./profiles %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/disable/%s'%os.path.basename(local_profilename)), True, 'Failed to create a symlink for %s in disable'%local_profilename)
|
||||
|
||||
|
||||
#Enable the ntpd profile and check if it was correctly re-enabled
|
||||
subprocess.check_output('%s ./../Tools/aa-disable -d ./profiles -r %s'%(python_interpreter, test_path), shell=True)
|
||||
|
||||
self.assertEqual(os.path.islink('./profiles/disable/%s'%os.path.basename(local_profilename)), False, 'Failed to remove a symlink for %s from disable'%local_profilename)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_autodep(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_cleanprof(self):
|
||||
input_file = 'cleanprof_test.in'
|
||||
output_file = 'cleanprof_test.out'
|
||||
|
@ -100,31 +100,31 @@ class Test(unittest.TestCase):
|
|||
shutil.copy('./%s'%input_file, './profiles')
|
||||
#Our silly test program whose profile we wish to clean
|
||||
cleanprof_test = '/usr/bin/a/simple/cleanprof/test/profile'
|
||||
|
||||
|
||||
subprocess.check_output('%s ./../Tools/aa-cleanprof -d ./profiles -s %s' % (python_interpreter, cleanprof_test), shell=True)
|
||||
|
||||
|
||||
#Strip off the first line (#modified line)
|
||||
subprocess.check_output('sed -i 1d ./profiles/%s'%(input_file), shell=True)
|
||||
|
||||
|
||||
self.assertEqual(filecmp.cmp('./profiles/%s'%input_file, './%s'%output_file, False), True, 'Failed to cleanup profile properly')
|
||||
|
||||
|
||||
|
||||
|
||||
def clean_profile_dir():
|
||||
#Wipe the local profiles from the test directory
|
||||
shutil.rmtree('./profiles')
|
||||
|
||||
if __name__ == "__main__":
|
||||
#import sys;sys.argv = ['', 'Test.testName']
|
||||
|
||||
|
||||
if os.path.exists('./profiles'):
|
||||
shutil.rmtree('./profiles')
|
||||
|
||||
#copy the local profiles to the test directory
|
||||
#Should be the set of cleanprofile
|
||||
shutil.copytree('/etc/apparmor.d', './profiles', symlinks=True)
|
||||
|
||||
|
||||
apparmor.profile_dir='./profiles'
|
||||
|
||||
atexit.register(clean_profile_dir)
|
||||
|
||||
|
||||
unittest.main()
|
||||
|
|
|
@ -8,18 +8,18 @@ sys.path.append('../')
|
|||
import apparmor.severity as severity
|
||||
from apparmor.common import AppArmorException
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
#copy the local profiles to the test directory
|
||||
if os.path.exists('./profiles'):
|
||||
shutil.rmtree('./profiles')
|
||||
shutil.copytree('/etc/apparmor.d/', './profiles/', symlinks=True)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
#Wipe the local profiles from the test directory
|
||||
shutil.rmtree('./profiles')
|
||||
|
||||
|
||||
def testRank_Test(self):
|
||||
s = severity.Severity('severity.db')
|
||||
rank = s.rank('/usr/bin/whatis', 'x')
|
||||
|
@ -42,35 +42,35 @@ class Test(unittest.TestCase):
|
|||
self.assertEqual(rank, 9, 'Wrong rank')
|
||||
self.assertEqual(s.rank('/etc/apparmor/**', 'r') , 6, 'Invalid Rank')
|
||||
self.assertEqual(s.rank('/etc/**', 'r') , 10, 'Invalid Rank')
|
||||
|
||||
|
||||
# Load all variables for /sbin/klogd and test them
|
||||
s.load_variables('profiles/sbin.klogd')
|
||||
self.assertEqual(s.rank('@{PROC}/sys/vm/overcommit_memory', 'r'), 6, 'Invalid Rank')
|
||||
self.assertEqual(s.rank('@{HOME}/sys/@{PROC}/overcommit_memory', 'r'), 10, 'Invalid Rank')
|
||||
self.assertEqual(s.rank('/overco@{multiarch}mmit_memory', 'r'), 10, 'Invalid Rank')
|
||||
|
||||
|
||||
s.unload_variables()
|
||||
|
||||
|
||||
s.load_variables('profiles/usr.sbin.dnsmasq')
|
||||
self.assertEqual(s.rank('@{PROC}/sys/@{TFTP_DIR}/overcommit_memory', 'r'), 6, 'Invalid Rank')
|
||||
self.assertEqual(s.rank('@{PROC}/sys/vm/overcommit_memory', 'r'), 6, 'Invalid Rank')
|
||||
self.assertEqual(s.rank('@{HOME}/sys/@{PROC}/overcommit_memory', 'r'), 10, 'Invalid Rank')
|
||||
self.assertEqual(s.rank('/overco@{multiarch}mmit_memory', 'r'), 10, 'Invalid Rank')
|
||||
|
||||
|
||||
#self.assertEqual(s.rank('/proc/@{PID}/maps', 'rw'), 9, 'Invalid Rank')
|
||||
|
||||
|
||||
def testInvalid(self):
|
||||
s = severity.Severity('severity.db')
|
||||
rank = s.rank('/dev/doublehit', 'i')
|
||||
self.assertEqual(rank, 10, 'Wrong')
|
||||
rank = s.rank('/dev/doublehit', 'i')
|
||||
self.assertEqual(rank, 10, 'Wrong')
|
||||
try:
|
||||
broken = severity.Severity('severity_broken.db')
|
||||
broken = severity.Severity('severity_broken.db')
|
||||
except AppArmorException:
|
||||
pass
|
||||
rank = s.rank('CAP_UNKOWN')
|
||||
rank = s.rank('CAP_K*')
|
||||
|
||||
|
||||
rank = s.rank('CAP_K*')
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
#import sys;sys.argv = ['', 'Test.testName']
|
||||
|
|
|
@ -115,13 +115,13 @@ while not done_profiling:
|
|||
|
||||
else:
|
||||
logmark = last_audit_entry_time()
|
||||
|
||||
|
||||
q=apparmor.hasher()
|
||||
q['headers'] = [_('Profiling'), program]
|
||||
q['functions'] = ['CMD_SCAN', 'CMD_FINISHED']
|
||||
q['default'] = 'CMD_SCAN'
|
||||
ans, arg = apparmor.UI_PromptUser(q, 'noexit')
|
||||
|
||||
|
||||
if ans == 'CMD_SCAN':
|
||||
lp_ret = apparmor.do_logprof_pass(logmark, passno)
|
||||
passno += 1
|
||||
|
|
|
@ -19,16 +19,16 @@ profiles = [args.mine, args.base, args.other]
|
|||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
print(profiles)
|
||||
|
||||
def main():
|
||||
mergeprofiles = Merge(profiles)
|
||||
|
||||
|
||||
class Merge(object):
|
||||
def __init__(self, profiles):
|
||||
user, base, other = profiles
|
||||
|
||||
|
||||
#Read and parse base profile and save profile data, include data from it and reset them
|
||||
apparmor.read_profile(base, True)
|
||||
base = cleanprof.Prof()
|
||||
|
@ -36,7 +36,7 @@ class Merge(object):
|
|||
#self.base_filelist = apparmor.filelist
|
||||
#self.base_include = apparmor.include
|
||||
reset()
|
||||
|
||||
|
||||
#Read and parse other profile and save profile data, include data from it and reset them
|
||||
apparmor.read_profile(other, True)
|
||||
other = cleanprof.prof()
|
||||
|
@ -44,36 +44,36 @@ class Merge(object):
|
|||
#self.other_filelist = apparmor.filelist
|
||||
#self.other_include = apparmor.include
|
||||
reset()
|
||||
|
||||
|
||||
#Read and parse user profile
|
||||
apparmor.read_profile(profiles[0], True)
|
||||
user = cleanprof.prof()
|
||||
#user_aa = apparmor.aa
|
||||
#user_filelist = apparmor.filelist
|
||||
#user_include = apparmor.include
|
||||
|
||||
|
||||
def reset():
|
||||
apparmor.aa = apparmor.hasher()
|
||||
apparmor.filelist = hasher()
|
||||
apparmor.include = dict()
|
||||
apparmor.existing_profiles = hasher()
|
||||
apparmor.original_aa = hasher()
|
||||
|
||||
|
||||
def clear_common(self):
|
||||
common_base_other()
|
||||
remove_common('base')
|
||||
remove_common('other')
|
||||
|
||||
|
||||
def common_base_other(self):
|
||||
pass
|
||||
|
||||
|
||||
def remove_common(self, profile):
|
||||
if prof1 == 'base':
|
||||
|
||||
|
||||
# def intersect(ra, rb):
|
||||
# """Given two ranges return the range where they intersect or None.
|
||||
#
|
||||
#
|
||||
# >>> intersect((0, 10), (0, 6))
|
||||
# (0, 6)
|
||||
# >>> intersect((0, 10), (5, 15))
|
||||
|
@ -84,15 +84,15 @@ class Merge(object):
|
|||
# (7, 9)
|
||||
# """
|
||||
# # preconditions: (ra[0] <= ra[1]) and (rb[0] <= rb[1])
|
||||
#
|
||||
#
|
||||
# sa = max(ra[0], rb[0])
|
||||
# sb = min(ra[1], rb[1])
|
||||
# if sa < sb:
|
||||
# return sa, sb
|
||||
# else:
|
||||
# return None
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# def compare_range(a, astart, aend, b, bstart, bend):
|
||||
# """Compare a[astart:aend] == b[bstart:bend], without slicing.
|
||||
# """
|
||||
|
@ -103,20 +103,20 @@ class Merge(object):
|
|||
# return False
|
||||
# else:
|
||||
# return True
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# class Merge3(object):
|
||||
# """3-way merge of texts.
|
||||
#
|
||||
#
|
||||
# Given BASE, OTHER, THIS, tries to produce a combined text
|
||||
# incorporating the changes from both BASE->OTHER and BASE->THIS.
|
||||
# All three will typically be sequences of lines."""
|
||||
#
|
||||
#
|
||||
# def __init__(self, base, a, b, is_cherrypick=False, allow_objects=False):
|
||||
# """Constructor.
|
||||
#
|
||||
#
|
||||
# :param base: lines in BASE
|
||||
# :param a: lines in A
|
||||
# :param b: lines in B
|
||||
|
@ -136,7 +136,7 @@ class Merge(object):
|
|||
# self.a = a
|
||||
# self.b = b
|
||||
# self.is_cherrypick = is_cherrypick
|
||||
#
|
||||
#
|
||||
# def merge_lines(self,
|
||||
# name_a=None,
|
||||
# name_b=None,
|
||||
|
@ -190,10 +190,10 @@ class Merge(object):
|
|||
# yield end_marker + newline
|
||||
# else:
|
||||
# raise ValueError(what)
|
||||
#
|
||||
#
|
||||
# def merge_annotated(self):
|
||||
# """Return merge with conflicts, showing origin of lines.
|
||||
#
|
||||
#
|
||||
# Most useful for debugging merge.
|
||||
# """
|
||||
# for t in self.merge_regions():
|
||||
|
@ -217,22 +217,22 @@ class Merge(object):
|
|||
# yield '>>>>\n'
|
||||
# else:
|
||||
# raise ValueError(what)
|
||||
#
|
||||
#
|
||||
# def merge_groups(self):
|
||||
# """Yield sequence of line groups. Each one is a tuple:
|
||||
#
|
||||
#
|
||||
# 'unchanged', lines
|
||||
# Lines unchanged from base
|
||||
#
|
||||
#
|
||||
# 'a', lines
|
||||
# Lines taken from a
|
||||
#
|
||||
#
|
||||
# 'same', lines
|
||||
# Lines taken from a (and equal to b)
|
||||
#
|
||||
#
|
||||
# 'b', lines
|
||||
# Lines taken from b
|
||||
#
|
||||
#
|
||||
# 'conflict', base_lines, a_lines, b_lines
|
||||
# Lines from base were changed to either a or b and conflict.
|
||||
# """
|
||||
|
@ -251,37 +251,37 @@ class Merge(object):
|
|||
# self.b[t[5]:t[6]])
|
||||
# else:
|
||||
# raise ValueError(what)
|
||||
#
|
||||
#
|
||||
# def merge_regions(self):
|
||||
# """Return sequences of matching and conflicting regions.
|
||||
#
|
||||
#
|
||||
# This returns tuples, where the first value says what kind we
|
||||
# have:
|
||||
#
|
||||
#
|
||||
# 'unchanged', start, end
|
||||
# Take a region of base[start:end]
|
||||
#
|
||||
#
|
||||
# 'same', astart, aend
|
||||
# b and a are different from base but give the same result
|
||||
#
|
||||
#
|
||||
# 'a', start, end
|
||||
# Non-clashing insertion from a[start:end]
|
||||
#
|
||||
#
|
||||
# Method is as follows:
|
||||
#
|
||||
#
|
||||
# The two sequences align only on regions which match the base
|
||||
# and both descendents. These are found by doing a two-way diff
|
||||
# of each one against the base, and then finding the
|
||||
# intersections between those regions. These "sync regions"
|
||||
# are by definition unchanged in both and easily dealt with.
|
||||
#
|
||||
#
|
||||
# The regions in between can be in any of three cases:
|
||||
# conflicted, or changed on only one side.
|
||||
# """
|
||||
#
|
||||
#
|
||||
# # section a[0:ia] has been disposed of, etc
|
||||
# iz = ia = ib = 0
|
||||
#
|
||||
#
|
||||
# for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
|
||||
# matchlen = zend - zmatch
|
||||
# # invariants:
|
||||
|
@ -295,14 +295,14 @@ class Merge(object):
|
|||
# # assert len_a >= 0
|
||||
# # assert len_b >= 0
|
||||
# # assert len_base >= 0
|
||||
#
|
||||
#
|
||||
# #print 'unmatched a=%d, b=%d' % (len_a, len_b)
|
||||
#
|
||||
#
|
||||
# if len_a or len_b:
|
||||
# # try to avoid actually slicing the lists
|
||||
# same = compare_range(self.a, ia, amatch,
|
||||
# self.b, ib, bmatch)
|
||||
#
|
||||
#
|
||||
# if same:
|
||||
# yield 'same', ia, amatch
|
||||
# else:
|
||||
|
@ -324,25 +324,25 @@ class Merge(object):
|
|||
# yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
|
||||
# else:
|
||||
# raise AssertionError("can't handle a=b=base but unmatched")
|
||||
#
|
||||
#
|
||||
# ia = amatch
|
||||
# ib = bmatch
|
||||
# iz = zmatch
|
||||
#
|
||||
#
|
||||
# # if the same part of the base was deleted on both sides
|
||||
# # that's OK, we can just skip it.
|
||||
#
|
||||
#
|
||||
# if matchlen > 0:
|
||||
# # invariants:
|
||||
# # assert ia == amatch
|
||||
# # assert ib == bmatch
|
||||
# # assert iz == zmatch
|
||||
#
|
||||
#
|
||||
# yield 'unchanged', zmatch, zend
|
||||
# iz = zend
|
||||
# ia = aend
|
||||
# ib = bend
|
||||
#
|
||||
#
|
||||
# def _refine_cherrypick_conflict(self, zstart, zend, astart, aend, bstart, bend):
|
||||
# """When cherrypicking b => a, ignore matches with b and base."""
|
||||
# # Do not emit regions which match, only regions which do not match
|
||||
|
@ -382,10 +382,10 @@ class Merge(object):
|
|||
# astart, aend, bstart + last_b_idx, bstart + b_idx)
|
||||
# if not yielded_a:
|
||||
# yield ('conflict', zstart, zend, astart, aend, bstart, bend)
|
||||
#
|
||||
#
|
||||
# def reprocess_merge_regions(self, merge_regions):
|
||||
# """Where there are conflict regions, remove the agreed lines.
|
||||
#
|
||||
#
|
||||
# Lines where both A and B have made the same changes are
|
||||
# eliminated.
|
||||
# """
|
||||
|
@ -413,19 +413,19 @@ class Merge(object):
|
|||
# reg = self.mismatch_region(next_a, amatch, next_b, bmatch)
|
||||
# if reg is not None:
|
||||
# yield reg
|
||||
#
|
||||
#
|
||||
# @staticmethod
|
||||
# def mismatch_region(next_a, region_ia, next_b, region_ib):
|
||||
# if next_a < region_ia or next_b < region_ib:
|
||||
# return 'conflict', None, None, next_a, region_ia, next_b, region_ib
|
||||
#
|
||||
#
|
||||
# def find_sync_regions(self):
|
||||
# """Return a list of sync regions, where both descendents match the base.
|
||||
#
|
||||
#
|
||||
# Generates a list of (base1, base2, a1, a2, b1, b2). There is
|
||||
# always a zero-length sync region at the end of all the files.
|
||||
# """
|
||||
#
|
||||
#
|
||||
# ia = ib = 0
|
||||
# amatches = patiencediff.PatienceSequenceMatcher(
|
||||
# None, self.base, self.a).get_matching_blocks()
|
||||
|
@ -433,13 +433,13 @@ class Merge(object):
|
|||
# None, self.base, self.b).get_matching_blocks()
|
||||
# len_a = len(amatches)
|
||||
# len_b = len(bmatches)
|
||||
#
|
||||
#
|
||||
# sl = []
|
||||
#
|
||||
#
|
||||
# while ia < len_a and ib < len_b:
|
||||
# abase, amatch, alen = amatches[ia]
|
||||
# bbase, bmatch, blen = bmatches[ib]
|
||||
#
|
||||
#
|
||||
# # there is an unconflicted block at i; how long does it
|
||||
# # extend? until whichever one ends earlier.
|
||||
# i = intersect((abase, abase+alen), (bbase, bbase+blen))
|
||||
|
@ -447,23 +447,23 @@ class Merge(object):
|
|||
# intbase = i[0]
|
||||
# intend = i[1]
|
||||
# intlen = intend - intbase
|
||||
#
|
||||
#
|
||||
# # found a match of base[i[0], i[1]]; this may be less than
|
||||
# # the region that matches in either one
|
||||
# # assert intlen <= alen
|
||||
# # assert intlen <= blen
|
||||
# # assert abase <= intbase
|
||||
# # assert bbase <= intbase
|
||||
#
|
||||
#
|
||||
# asub = amatch + (intbase - abase)
|
||||
# bsub = bmatch + (intbase - bbase)
|
||||
# aend = asub + intlen
|
||||
# bend = bsub + intlen
|
||||
#
|
||||
#
|
||||
# # assert self.base[intbase:intend] == self.a[asub:aend], \
|
||||
# # (self.base[intbase:intend], self.a[asub:aend])
|
||||
# # assert self.base[intbase:intend] == self.b[bsub:bend]
|
||||
#
|
||||
#
|
||||
# sl.append((intbase, intend,
|
||||
# asub, aend,
|
||||
# bsub, bend))
|
||||
|
@ -472,23 +472,23 @@ class Merge(object):
|
|||
# ia += 1
|
||||
# else:
|
||||
# ib += 1
|
||||
#
|
||||
#
|
||||
# intbase = len(self.base)
|
||||
# abase = len(self.a)
|
||||
# bbase = len(self.b)
|
||||
# sl.append((intbase, intbase, abase, abase, bbase, bbase))
|
||||
#
|
||||
#
|
||||
# return sl
|
||||
#
|
||||
#
|
||||
# def find_unconflicted(self):
|
||||
# """Return a list of ranges in base that are not conflicted."""
|
||||
# am = patiencediff.PatienceSequenceMatcher(
|
||||
# None, self.base, self.a).get_matching_blocks()
|
||||
# bm = patiencediff.PatienceSequenceMatcher(
|
||||
# None, self.base, self.b).get_matching_blocks()
|
||||
#
|
||||
#
|
||||
# unc = []
|
||||
#
|
||||
#
|
||||
# while am and bm:
|
||||
# # there is an unconflicted block at i; how long does it
|
||||
# # extend? until whichever one ends earlier.
|
||||
|
@ -499,18 +499,18 @@ class Merge(object):
|
|||
# i = intersect((a1, a2), (b1, b2))
|
||||
# if i:
|
||||
# unc.append(i)
|
||||
#
|
||||
#
|
||||
# if a2 < b2:
|
||||
# del am[0]
|
||||
# else:
|
||||
# del bm[0]
|
||||
#
|
||||
#
|
||||
# return unc
|
||||
#
|
||||
#
|
||||
# a = file(profiles[0], 'rt').readlines()
|
||||
# base = file(profiles[1], 'rt').readlines()
|
||||
# b = file(profiles[2], 'rt').readlines()
|
||||
#
|
||||
#
|
||||
# m3 = Merge3(base, a, b)
|
||||
#
|
||||
#
|
||||
# sys.stdout.write(m3.merge_annotated())
|
|
@ -23,7 +23,7 @@ else:
|
|||
regex_tcp_udp = re.compile('^(tcp|udp)\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\s+)\s+(\d+)\/(\S+)')
|
||||
import subprocess
|
||||
output = subprocess.check_output('LANG=C netstat -nlp', shell=True).split('\n')
|
||||
|
||||
|
||||
for line in output:
|
||||
match = regex_tcp_udp.search(line)
|
||||
if match:
|
||||
|
@ -42,7 +42,7 @@ for pid in sorted(pids):
|
|||
for line in current:
|
||||
if line.startswith('/') or line.startswith('null'):
|
||||
attr = line.strip()
|
||||
|
||||
|
||||
cmdline = apparmor.cmd(['cat', '/proc/%s/cmdline'%pid])[1]
|
||||
pname = cmdline.split('\0')[0]
|
||||
if '/' in pname and pname != prog:
|
||||
|
|
|
@ -10,5 +10,5 @@ def init_localisation():
|
|||
except IOError:
|
||||
trans = gettext.NullTranslations()
|
||||
trans.install()
|
||||
|
||||
|
||||
init_localisation()
|
991
apparmor/aa.py
991
apparmor/aa.py
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,7 @@ AA_EXEC_TYPE = (AA_MAY_EXEC | AA_EXEC_UNSAFE | AA_EXEC_INHERIT |
|
|||
|
||||
ALL_AA_EXEC_TYPE = AA_EXEC_TYPE
|
||||
|
||||
MODE_HASH = {'x': AA_MAY_EXEC, 'X': AA_MAY_EXEC,
|
||||
MODE_HASH = {'x': AA_MAY_EXEC, 'X': AA_MAY_EXEC,
|
||||
'w': AA_MAY_WRITE, 'W': AA_MAY_WRITE,
|
||||
'r': AA_MAY_READ, 'R': AA_MAY_READ,
|
||||
'a': AA_MAY_APPEND, 'A': AA_MAY_APPEND,
|
||||
|
@ -84,7 +84,7 @@ def sub_str_to_mode(string):
|
|||
mode |= MODE_HASH[tmp]
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
return mode
|
||||
|
||||
def split_log_mode(mode):
|
||||
|
@ -102,10 +102,10 @@ def split_log_mode(mode):
|
|||
def mode_contains(mode, subset):
|
||||
# w implies a
|
||||
if mode & AA_MAY_WRITE:
|
||||
mode |= AA_MAY_APPEND
|
||||
mode |= AA_MAY_APPEND
|
||||
if mode & (AA_OTHER(AA_MAY_WRITE)):
|
||||
mode |= (AA_OTHER(AA_MAY_APPEND))
|
||||
|
||||
|
||||
return (mode & subset) == subset
|
||||
|
||||
def contains(mode, string):
|
||||
|
@ -128,7 +128,7 @@ def map_log_mode(mode):
|
|||
def print_mode(mode):
|
||||
user, other = split_mode(mode)
|
||||
string = sub_mode_to_str(user) + '::' + sub_mode_to_str(other)
|
||||
|
||||
|
||||
return string
|
||||
|
||||
def sub_mode_to_str(mode):
|
||||
|
@ -137,7 +137,7 @@ def sub_mode_to_str(mode):
|
|||
if mode & AA_MAY_WRITE:
|
||||
mode = mode - AA_MAY_APPEND
|
||||
#string = ''.join(mode)
|
||||
|
||||
|
||||
if mode & AA_EXEC_MMAP:
|
||||
string += 'm'
|
||||
if mode & AA_MAY_READ:
|
||||
|
@ -150,37 +150,37 @@ def sub_mode_to_str(mode):
|
|||
string += 'l'
|
||||
if mode & AA_MAY_LOCK:
|
||||
string += 'k'
|
||||
|
||||
|
||||
# modes P and C must appear before I and U else invalid syntax
|
||||
if mode & (AA_EXEC_PROFILE | AA_EXEC_NT):
|
||||
if mode & AA_EXEC_UNSAFE:
|
||||
string += 'p'
|
||||
else:
|
||||
string += 'P'
|
||||
|
||||
|
||||
if mode & AA_EXEC_CHILD:
|
||||
if mode & AA_EXEC_UNSAFE:
|
||||
string += 'c'
|
||||
else:
|
||||
string += 'C'
|
||||
|
||||
|
||||
if mode & AA_EXEC_UNCONFINED:
|
||||
if mode & AA_EXEC_UNSAFE:
|
||||
string += 'u'
|
||||
else:
|
||||
string += 'U'
|
||||
|
||||
|
||||
if mode & AA_EXEC_INHERIT:
|
||||
string += 'i'
|
||||
|
||||
|
||||
if mode & AA_MAY_EXEC:
|
||||
string += 'x'
|
||||
|
||||
|
||||
return string
|
||||
|
||||
def is_user_mode(mode):
|
||||
user, other = split_mode(mode)
|
||||
|
||||
|
||||
if user and not other:
|
||||
return True
|
||||
else:
|
||||
|
@ -195,7 +195,7 @@ def split_mode(mode):
|
|||
if not '::' in i:
|
||||
user.add(i)
|
||||
other = mode - user
|
||||
other = AA_OTHER_REMOVE(other)
|
||||
other = AA_OTHER_REMOVE(other)
|
||||
return user, other
|
||||
|
||||
def mode_to_str(mode):
|
||||
|
@ -205,11 +205,11 @@ def mode_to_str(mode):
|
|||
def flatten_mode(mode):
|
||||
if not mode:
|
||||
return set()
|
||||
|
||||
|
||||
user, other = split_mode(mode)
|
||||
mode = user | other
|
||||
mode |= (AA_OTHER(mode))
|
||||
|
||||
|
||||
return mode
|
||||
|
||||
def owner_flatten_mode(mode):
|
||||
|
@ -219,22 +219,22 @@ def owner_flatten_mode(mode):
|
|||
def mode_to_str_user(mode):
|
||||
user, other = split_mode(mode)
|
||||
string = ''
|
||||
|
||||
|
||||
if not user:
|
||||
user = set()
|
||||
if not other:
|
||||
other = set()
|
||||
|
||||
|
||||
if user - other:
|
||||
if other:
|
||||
string = sub_mode_to_str(other) + '+'
|
||||
string += 'owner ' + sub_mode_to_str(user - other)
|
||||
|
||||
|
||||
elif is_user_mode(mode):
|
||||
string = 'owner ' + sub_mode_to_str(user)
|
||||
else:
|
||||
string = sub_mode_to_str(flatten_mode(mode))
|
||||
|
||||
|
||||
return string
|
||||
|
||||
def log_str_to_mode(profile, string, nt_name):
|
||||
|
@ -247,7 +247,7 @@ def log_str_to_mode(profile, string, nt_name):
|
|||
if match:
|
||||
lprofile, lhat = match.groups()
|
||||
tmode = 0
|
||||
|
||||
|
||||
if lprofile == profile:
|
||||
if mode & AA_MAY_EXEC:
|
||||
tmode = str_to_mode('Cx::')
|
||||
|
@ -260,8 +260,8 @@ def log_str_to_mode(profile, string, nt_name):
|
|||
if mode & AA_OTHER(AA_MAY_EXEC):
|
||||
tmode |= str_to_mode('Px')
|
||||
nt_name = lhat
|
||||
|
||||
|
||||
mode = mode - str_to_mode('Nx')
|
||||
mode |= tmode
|
||||
|
||||
|
||||
return mode, nt_name
|
|
@ -9,24 +9,24 @@ class Prof:
|
|||
self.filelist = apparmor.aa.filelist
|
||||
self.include = apparmor.aa.include
|
||||
self.filename = filename
|
||||
|
||||
|
||||
class CleanProf:
|
||||
def __init__(self, same_file, profile, other):
|
||||
#If same_file we're basically comparing the file against itself to check superfluous rules
|
||||
self.same_file = same_file
|
||||
self.profile = profile
|
||||
self.other = profile
|
||||
|
||||
|
||||
def compare_profiles(self):
|
||||
#Remove the duplicate file-level includes from other
|
||||
other_file_includes = list(self.other.profile.filename['include'].keys())
|
||||
for rule in self.profile.filelist[self.profile.filename]:
|
||||
if rule in other_file_includes:
|
||||
self.other.other.filename['include'].pop(rule)
|
||||
|
||||
|
||||
for profile in self.profile.aa.keys():
|
||||
self.remove_duplicate_rules(profile)
|
||||
|
||||
|
||||
def remove_duplicate_rules(self, program):
|
||||
#Process the profile of the program
|
||||
#Process every hat in the profile individually
|
||||
|
@ -35,25 +35,25 @@ class CleanProf:
|
|||
for hat in self.profile.aa[program].keys():
|
||||
#The combined list of includes from profile and the file
|
||||
includes = list(self.profile.aa[program][hat]['include'].keys()) + file_includes
|
||||
|
||||
#Clean up superfluous rules from includes in the other profile
|
||||
|
||||
#Clean up superfluous rules from includes in the other profile
|
||||
for inc in includes:
|
||||
if not self.profile.include.get(inc, {}).get(inc,False):
|
||||
apparmor.aa.load_include(inc)
|
||||
deleted += apparmor.aa.delete_duplicates(self.other.aa[program][hat], inc)
|
||||
|
||||
|
||||
#Clean the duplicates of caps in other profile
|
||||
deleted += self.delete_cap_duplicates(self.profile.aa[program][hat]['allow']['capability'], self.other.aa[program][hat]['allow']['capability'], self.same_file)
|
||||
deleted += self.delete_cap_duplicates(self.profile.aa[program][hat]['allow']['capability'], self.other.aa[program][hat]['allow']['capability'], self.same_file)
|
||||
deleted += self.delete_cap_duplicates(self.profile.aa[program][hat]['deny']['capability'], self.other.aa[program][hat]['deny']['capability'], self.same_file)
|
||||
|
||||
#Clean the duplicates of path in other profile
|
||||
deleted += self.delete_path_duplicates(self.profile.aa[program][hat], self.other.aa[program][hat], 'allow', self.same_file)
|
||||
deleted += self.delete_path_duplicates(self.profile.aa[program][hat], self.other.aa[program][hat], 'deny', self.same_file)
|
||||
|
||||
|
||||
#Clean the duplicates of net rules in other profile
|
||||
deleted += self.delete_net_duplicates(self.profile.aa[program][hat]['allow']['netdomain'], self.other.aa[program][hat]['allow']['netdomain'], self.same_file)
|
||||
deleted += self.delete_net_duplicates(self.profile.aa[program][hat]['deny']['netdomain'], self.other.aa[program][hat]['deny']['netdomain'], self.same_file)
|
||||
|
||||
|
||||
return deleted
|
||||
|
||||
def delete_path_duplicates(self, profile, profile_other, allow, same_profile=True):
|
||||
|
@ -73,14 +73,14 @@ class CleanProf:
|
|||
cm = profile[allow]['path'][rule]['mode']
|
||||
am = profile[allow]['path'][rule]['audit']
|
||||
#If modes of rule are a superset of rules implied by entry we can safely remove it
|
||||
if apparmor.aa.mode_contains(cm, profile_other[allow]['path'][entry]['mode']) and apparmor.aa.mode_contains(am, profile_other[allow]['path'][entry]['audit']):
|
||||
if apparmor.aa.mode_contains(cm, profile_other[allow]['path'][entry]['mode']) and apparmor.aa.mode_contains(am, profile_other[allow]['path'][entry]['audit']):
|
||||
deleted.append(entry)
|
||||
|
||||
for entry in deleted:
|
||||
profile_other[allow]['path'].pop(entry)
|
||||
|
||||
return len(deleted)
|
||||
|
||||
|
||||
def delete_cap_duplicates(self, profilecaps, profilecaps_other, same_profile=True):
|
||||
deleted = []
|
||||
if profilecaps and profilecaps_other and not same_profile:
|
||||
|
@ -89,9 +89,9 @@ class CleanProf:
|
|||
deleted.append(capname)
|
||||
for capname in deleted:
|
||||
profilecaps_other.pop(capname)
|
||||
|
||||
|
||||
return len(deleted)
|
||||
|
||||
|
||||
def delete_net_duplicates(self, netrules, netrules_other, same_profile=True):
|
||||
deleted = 0
|
||||
copy_netrules_other = copy.deepcopy(netrules_other)
|
||||
|
@ -108,7 +108,7 @@ class CleanProf:
|
|||
deleted += len(netrules['rule'][fam].keys())
|
||||
else:
|
||||
deleted += 1
|
||||
netrules_other['rule'].pop(fam)
|
||||
netrules_other['rule'].pop(fam)
|
||||
elif type(netrules_other['rule'][fam]) != dict and netrules_other['rule'][fam]:
|
||||
if type(netrules['rule'][fam]) != dict and netrules['rule'][fam]:
|
||||
if not same_profile:
|
||||
|
|
|
@ -147,7 +147,7 @@ def readkey():
|
|||
ch = sys.stdin.read(1)
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
|
||||
|
||||
return ch
|
||||
|
||||
def hasher():
|
||||
|
@ -160,20 +160,20 @@ def convert_regexp(regexp):
|
|||
regex_paren = re.compile('^(.*){([^}]*)}(.*)$')
|
||||
regexp = regexp.strip()
|
||||
new_reg = re.sub(r'(?<!\\)(\.|\+|\$)',r'\\\1',regexp)
|
||||
|
||||
|
||||
while regex_paren.search(new_reg):
|
||||
match = regex_paren.search(new_reg).groups()
|
||||
prev = match[0]
|
||||
after = match[2]
|
||||
p1 = match[1].replace(',','|')
|
||||
new_reg = prev+'('+p1+')'+after
|
||||
|
||||
|
||||
new_reg = new_reg.replace('?', '[^/\000]')
|
||||
|
||||
|
||||
multi_glob = '__KJHDKVZH_AAPROF_INTERNAL_GLOB_SVCUZDGZID__'
|
||||
new_reg = new_reg.replace('**', multi_glob)
|
||||
#print(new_reg)
|
||||
|
||||
|
||||
# Match atleast one character if * or ** after /
|
||||
# ?< is the negative lookback operator
|
||||
new_reg = new_reg.replace('*', '(((?<=/)[^/\000]+)|((?<!/)[^/\000]*))')
|
||||
|
@ -185,9 +185,9 @@ def convert_regexp(regexp):
|
|||
return new_reg
|
||||
|
||||
class DebugLogger:
|
||||
def __init__(self, module_name=__name__):
|
||||
def __init__(self, module_name=__name__):
|
||||
self.debugging = False
|
||||
self.debug_level = logging.DEBUG
|
||||
self.debug_level = logging.DEBUG
|
||||
if os.getenv('LOGPROF_DEBUG', False):
|
||||
self.debugging = os.getenv('LOGPROF_DEBUG')
|
||||
try:
|
||||
|
@ -203,13 +203,13 @@ class DebugLogger:
|
|||
self.debug_level = logging.INFO
|
||||
elif self.debugging == 3:
|
||||
self.debug_level = logging.DEBUG
|
||||
|
||||
|
||||
|
||||
|
||||
logging.basicConfig(filename='/var/log/apparmor/logprof.log', level=self.debug_level, format='%(asctime)s - %(name)s - %(message)s\n')
|
||||
|
||||
|
||||
self.logger = logging.getLogger(module_name)
|
||||
|
||||
|
||||
|
||||
|
||||
def error(self, msg):
|
||||
if self.debugging:
|
||||
self.logger.error(msg)
|
||||
|
|
|
@ -16,10 +16,10 @@ if sys.version_info < (3,0):
|
|||
section_options[option] = value
|
||||
return section_options
|
||||
|
||||
|
||||
|
||||
else:
|
||||
import configparser
|
||||
|
||||
|
||||
|
||||
from apparmor.common import AppArmorException, warn, msg, open_file_read
|
||||
|
||||
|
@ -36,16 +36,16 @@ class Config:
|
|||
self.input_file = None
|
||||
else:
|
||||
raise AppArmorException("Unknown configuration file type")
|
||||
|
||||
|
||||
def new_config(self):
|
||||
if self.conf_type == 'shell':
|
||||
config = {'': dict()}
|
||||
elif self.conf_type == 'ini':
|
||||
config = configparser.ConfigParser()
|
||||
return config
|
||||
|
||||
|
||||
def read_config(self, filename):
|
||||
"""Reads the file and returns a config[section][attribute]=property object"""
|
||||
"""Reads the file and returns a config[section][attribute]=property object"""
|
||||
# LP: Bug #692406
|
||||
# Explicitly disabled repository
|
||||
filepath = self.CONF_DIR + '/' + filename
|
||||
|
@ -63,7 +63,7 @@ class Config:
|
|||
# Set the option form to string -prevents forced conversion to lowercase
|
||||
config.optionxform = str
|
||||
if sys.version_info > (3,0):
|
||||
config.read(filepath)
|
||||
config.read(filepath)
|
||||
else:
|
||||
try:
|
||||
config.read(filepath)
|
||||
|
@ -72,7 +72,7 @@ class Config:
|
|||
config.read(tmp_filepath.name)
|
||||
##config.__get__()
|
||||
return config
|
||||
|
||||
|
||||
def write_config(self, filename, config):
|
||||
"""Writes the given config to the specified file"""
|
||||
filepath = self.CONF_DIR + '/' + filename
|
||||
|
@ -96,8 +96,8 @@ class Config:
|
|||
else:
|
||||
# Replace the target config file with the temporary file
|
||||
os.rename(config_file.name, filepath)
|
||||
|
||||
|
||||
|
||||
|
||||
def find_first_file(self, file_list):
|
||||
"""Returns name of first matching file None otherwise"""
|
||||
filename = None
|
||||
|
@ -106,7 +106,7 @@ class Config:
|
|||
filename = file
|
||||
break
|
||||
return filename
|
||||
|
||||
|
||||
def find_first_dir(self, dir_list):
|
||||
"""Returns name of first matching directory None otherwise"""
|
||||
dirname = None
|
||||
|
@ -116,7 +116,7 @@ class Config:
|
|||
dirname = direc
|
||||
break
|
||||
return dirname
|
||||
|
||||
|
||||
def read_shell(self, filepath):
|
||||
"""Reads the shell type conf files and returns config[''][option]=value"""
|
||||
config = {'': dict()}
|
||||
|
@ -134,7 +134,7 @@ class Config:
|
|||
value = None
|
||||
config[''][option] = value
|
||||
return config
|
||||
|
||||
|
||||
def write_shell(self, filepath, f_out, config):
|
||||
"""Writes the config object in shell file format"""
|
||||
# All the options in the file
|
||||
|
@ -153,8 +153,8 @@ class Config:
|
|||
comment = value.split('#', 1)[1]
|
||||
comment = '#'+comment
|
||||
else:
|
||||
comment = ''
|
||||
# If option exists in the new config file
|
||||
comment = ''
|
||||
# If option exists in the new config file
|
||||
if option in options:
|
||||
# If value is different
|
||||
if value != config[''][option]:
|
||||
|
@ -174,7 +174,7 @@ class Config:
|
|||
# If option type
|
||||
option = result[0]
|
||||
value = None
|
||||
# If option exists in the new config file
|
||||
# If option exists in the new config file
|
||||
if option in options:
|
||||
# If its no longer option type
|
||||
if config[''][option] != None:
|
||||
|
@ -182,7 +182,7 @@ class Config:
|
|||
line = option + '=' + value + '\n'
|
||||
f_out.write(line)
|
||||
# Remove from remaining options list
|
||||
options.remove(option)
|
||||
options.remove(option)
|
||||
else:
|
||||
# If its empty or comment copy as it is
|
||||
f_out.write(line)
|
||||
|
@ -197,7 +197,7 @@ class Config:
|
|||
else:
|
||||
line = option + '=' + value + '\n'
|
||||
f_out.write(line)
|
||||
|
||||
|
||||
def write_configparser(self, filepath, f_out, config):
|
||||
"""Writes/updates the given file with given config object"""
|
||||
# All the sections in the file
|
||||
|
@ -229,21 +229,21 @@ class Config:
|
|||
f_out.write(line)
|
||||
else:
|
||||
# disable writing until next valid section
|
||||
write = False
|
||||
# If write enabled
|
||||
write = False
|
||||
# If write enabled
|
||||
elif write:
|
||||
value = shlex.split(line, True)
|
||||
# If the line is empty or a comment
|
||||
if not value:
|
||||
f_out.write(line)
|
||||
else:
|
||||
option, value = line.split('=', 1)
|
||||
option, value = line.split('=', 1)
|
||||
try:
|
||||
# split any inline comments
|
||||
value, comment = value.split('#', 1)
|
||||
comment = '#' + comment
|
||||
except ValueError:
|
||||
comment = ''
|
||||
comment = ''
|
||||
if option.strip() in options:
|
||||
if config[section][option.strip()] != value.strip():
|
||||
value = value.replace(value, config[section][option.strip()])
|
||||
|
@ -264,7 +264,7 @@ class Config:
|
|||
options = config.options(section)
|
||||
for option in options:
|
||||
line = ' ' + option + ' = ' + config[section][option] + '\n'
|
||||
f_out.write(line)
|
||||
f_out.write(line)
|
||||
|
||||
def py2_parser(filename):
|
||||
"""Returns the de-dented ini file from the new format ini"""
|
||||
|
|
|
@ -3,7 +3,7 @@ import re
|
|||
import sys
|
||||
import time
|
||||
import LibAppArmor
|
||||
from apparmor.common import (AppArmorException, error, debug, msg,
|
||||
from apparmor.common import (AppArmorException, error, debug, msg,
|
||||
open_file_read, valid_path,
|
||||
hasher, open_file_write, convert_regexp, DebugLogger)
|
||||
|
||||
|
@ -45,7 +45,7 @@ class ReadLog:
|
|||
self.logmark = ''
|
||||
self.seenmark = None
|
||||
self.next_log_entry = None
|
||||
|
||||
|
||||
def prefetch_next_log_entry(self):
|
||||
if self.next_log_entry:
|
||||
sys.stderr.out('A log entry already present: %s' % self.next_log_entry)
|
||||
|
@ -54,7 +54,7 @@ class ReadLog:
|
|||
self.next_log_entry = self.LOG.readline()
|
||||
if not self.next_log_entry:
|
||||
break
|
||||
|
||||
|
||||
def get_next_log_entry(self):
|
||||
# If no next log entry fetch it
|
||||
if not self.next_log_entry:
|
||||
|
@ -62,22 +62,22 @@ class ReadLog:
|
|||
log_entry = self.next_log_entry
|
||||
self.next_log_entry = None
|
||||
return log_entry
|
||||
|
||||
|
||||
def peek_at_next_log_entry(self):
|
||||
# Take a peek at the next log entry
|
||||
if not self.next_log_entry:
|
||||
self.prefetch_next_log_entry()
|
||||
return self.next_log_entry
|
||||
|
||||
|
||||
def throw_away_next_log_entry(self):
|
||||
self.next_log_entry = None
|
||||
|
||||
|
||||
def parse_log_record(self, record):
|
||||
self.debug_logger.debug('parse_log_record: %s' % record)
|
||||
|
||||
|
||||
record_event = self.parse_event(record)
|
||||
return record_event
|
||||
|
||||
|
||||
def parse_event(self, msg):
|
||||
"""Parse the event from log into key value pairs"""
|
||||
msg = msg.strip()
|
||||
|
@ -122,21 +122,21 @@ class ReadLog:
|
|||
raise AppArmorException(_('Log contains unknown mode %s') % dmask)
|
||||
#print('parse_event:', ev['profile'], dmask, ev['name2'])
|
||||
mask, name = log_str_to_mode(ev['profile'], dmask, ev['name2'])
|
||||
|
||||
|
||||
ev['denied_mask'] = mask
|
||||
ev['name2'] = name
|
||||
|
||||
|
||||
mask, name = log_str_to_mode(ev['profile'], rmask, ev['name2'])
|
||||
ev['request_mask'] = mask
|
||||
ev['name2'] = name
|
||||
|
||||
|
||||
if not ev['time']:
|
||||
ev['time'] = int(time.time())
|
||||
# Remove None keys
|
||||
#for key in ev.keys():
|
||||
# if not ev[key] or not re.search('[\w]+', ev[key]):
|
||||
# ev.pop(key)
|
||||
|
||||
|
||||
if ev['aamode']:
|
||||
# Convert aamode values to their counter-parts
|
||||
mode_convertor = {
|
||||
|
@ -152,13 +152,13 @@ class ReadLog:
|
|||
ev['aamode'] = mode_convertor[ev['aamode']]
|
||||
except KeyError:
|
||||
ev['aamode'] = None
|
||||
|
||||
|
||||
if ev['aamode']:
|
||||
#debug_logger.debug(ev)
|
||||
return ev
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def add_to_tree(self, loc_pid, parent, type, event):
|
||||
self.debug_logger.info('add_to_tree: pid [%s] type [%s] event [%s]' % (loc_pid, type, event))
|
||||
if not self.pid.get(loc_pid, False):
|
||||
|
@ -200,27 +200,27 @@ class ReadLog:
|
|||
aamode = 'ERROR'
|
||||
else:
|
||||
aamode = 'UNKNOWN'
|
||||
|
||||
|
||||
if aamode in ['UNKNOWN', 'AUDIT', 'STATUS', 'ERROR']:
|
||||
return None
|
||||
|
||||
|
||||
if 'profile_set' in e['operation']:
|
||||
return None
|
||||
|
||||
# Skip if AUDIT event was issued due to a change_hat in unconfined mode
|
||||
if not e.get('profile', False):
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
# Convert new null profiles to old single level null profile
|
||||
if '//null-' in e['profile']:
|
||||
e['profile'] = 'null-complain-profile'
|
||||
|
||||
|
||||
profile = e['profile']
|
||||
hat = None
|
||||
|
||||
|
||||
if '//' in e['profile']:
|
||||
profile, hat = e['profile'].split('//')[:2]
|
||||
|
||||
|
||||
# Filter out change_hat events that aren't from learning
|
||||
if e['operation'] == 'change_hat':
|
||||
if aamode != 'HINT' and aamode != 'PERMITTING':
|
||||
|
@ -229,18 +229,18 @@ class ReadLog:
|
|||
#hat = None
|
||||
if '//' in e['name']:
|
||||
profile, hat = e['name'].split('//')[:2]
|
||||
|
||||
|
||||
if not hat:
|
||||
hat = profile
|
||||
|
||||
# prog is no longer passed around consistently
|
||||
prog = 'HINT'
|
||||
|
||||
|
||||
if profile != 'null-complain-profile' and not self.profile_exists(profile):
|
||||
return None
|
||||
if e['operation'] == 'exec':
|
||||
if e.get('info', False) and e['info'] == 'mandatory profile missing':
|
||||
self.add_to_tree(e['pid'], e['parent'], 'exec',
|
||||
self.add_to_tree(e['pid'], e['parent'], 'exec',
|
||||
[profile, hat, aamode, 'PERMITTING', e['denied_mask'], e['name'], e['name2']])
|
||||
elif e.get('name2', False) and '\\null-/' in e['name2']:
|
||||
self.add_to_tree(e['pid'], e['parent'], 'exec',
|
||||
|
@ -250,11 +250,11 @@ class ReadLog:
|
|||
[profile, hat, prog, aamode, e['denied_mask'], e['name'], ''])
|
||||
else:
|
||||
self.debug_logger.debug('add_event_to_tree: dropped exec event in %s' % e['profile'])
|
||||
|
||||
|
||||
elif 'file_' in e['operation']:
|
||||
self.add_to_tree(e['pid'], e['parent'], 'path',
|
||||
[profile, hat, prog, aamode, e['denied_mask'], e['name'], ''])
|
||||
elif e['operation'] in ['open', 'truncate', 'mkdir', 'mknod', 'rename_src',
|
||||
elif e['operation'] in ['open', 'truncate', 'mkdir', 'mknod', 'rename_src',
|
||||
'rename_dest', 'unlink', 'rmdir', 'symlink_create', 'link']:
|
||||
#print(e['operation'], e['name'])
|
||||
self.add_to_tree(e['pid'], e['parent'], 'path',
|
||||
|
@ -274,18 +274,18 @@ class ReadLog:
|
|||
if entry and entry.get('info', False) == 'set profile':
|
||||
is_domain_change = True
|
||||
self.throw_away_next_log_entry()
|
||||
|
||||
|
||||
if is_domain_change:
|
||||
self.add_to_tree(e['pid'], e['parent'], 'exec',
|
||||
[profile, hat, prog, aamode, e['denied_mask'], e['name'], e['name2']])
|
||||
else:
|
||||
self.add_to_tree(e['pid'], e['parent'], 'path',
|
||||
[profile, hat, prog, aamode, e['denied_mask'], e['name'], ''])
|
||||
|
||||
|
||||
elif e['operation'] == 'sysctl':
|
||||
self.add_to_tree(e['pid'], e['parent'], 'path',
|
||||
[profile, hat, prog, aamode, e['denied_mask'], e['name'], ''])
|
||||
|
||||
|
||||
elif e['operation'] == 'clone':
|
||||
parent , child = e['pid'], e['task']
|
||||
if not parent:
|
||||
|
@ -305,7 +305,7 @@ class ReadLog:
|
|||
# else:
|
||||
# self.log += [arrayref]
|
||||
# self.pid[child] = arrayref
|
||||
|
||||
|
||||
elif self.op_type(e['operation']) == 'net':
|
||||
self.add_to_tree(e['pid'], e['parent'], 'netdomain',
|
||||
[profile, hat, prog, aamode, e['family'], e['sock_type'], e['protocol']])
|
||||
|
@ -314,7 +314,7 @@ class ReadLog:
|
|||
[profile, hat, aamode, hat])
|
||||
else:
|
||||
self.debug_logger.debug('UNHANDLED: %s' % e)
|
||||
|
||||
|
||||
def read_log(self, logmark):
|
||||
self.logmark = logmark
|
||||
seenmark = True
|
||||
|
@ -337,11 +337,11 @@ class ReadLog:
|
|||
self.debug_logger.debug('read_log: %s' % line)
|
||||
if self.logmark in line:
|
||||
seenmark = True
|
||||
|
||||
|
||||
self.debug_logger.debug('read_log: seenmark = %s' %seenmark)
|
||||
if not seenmark:
|
||||
continue
|
||||
|
||||
|
||||
event = self.parse_log_record(line)
|
||||
#print(event)
|
||||
if event:
|
||||
|
@ -349,12 +349,12 @@ class ReadLog:
|
|||
self.LOG.close()
|
||||
self.logmark = ''
|
||||
return self.log
|
||||
|
||||
|
||||
def op_type(self, operation):
|
||||
"""Returns the operation type if known, unkown otherwise"""
|
||||
operation_type = self.OPERATION_TYPES.get(operation, 'unknown')
|
||||
return operation_type
|
||||
|
||||
|
||||
def profile_exists(self, program):
|
||||
"""Returns True if profile exists, False otherwise"""
|
||||
# Check cache of profiles
|
||||
|
@ -368,8 +368,8 @@ class ReadLog:
|
|||
self.existing_profiles[program] = prof_path
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
def get_profile_filename(self, profile):
|
||||
"""Returns the full profile name"""
|
||||
if profile.startswith('/'):
|
||||
|
|
|
@ -17,7 +17,7 @@ class Severity:
|
|||
self.severity['VARIABLES'] = dict()
|
||||
if not dbname:
|
||||
return None
|
||||
|
||||
|
||||
with open_file_read(dbname) as database:#open(dbname, 'r')
|
||||
for lineno, line in enumerate(database, start=1):
|
||||
line = line.strip() # or only rstrip and lstrip?
|
||||
|
@ -61,7 +61,7 @@ class Severity:
|
|||
self.severity['CAPABILITIES'][resource] = severity
|
||||
else:
|
||||
raise AppArmorException("Unexpected line in file: %s\n\t[Line %s]: %s" % (dbname, lineno, line))
|
||||
|
||||
|
||||
def handle_capability(self, resource):
|
||||
"""Returns the severity of for the capability resource, default value if no match"""
|
||||
if resource in self.severity['CAPABILITIES'].keys():
|
||||
|
@ -69,8 +69,8 @@ class Severity:
|
|||
# raise ValueError("unexpected capability rank input: %s"%resource)
|
||||
warn("unknown capability: %s" % resource)
|
||||
return self.severity['DEFAULT_RANK']
|
||||
|
||||
|
||||
|
||||
|
||||
def check_subtree(self, tree, mode, sev, segments):
|
||||
"""Returns the max severity from the regex tree"""
|
||||
if len(segments) == 0:
|
||||
|
@ -89,13 +89,13 @@ class Severity:
|
|||
if '*' in chunk:
|
||||
# Match rest of the path
|
||||
if re.search("^"+chunk, path):
|
||||
# Find max rank
|
||||
# Find max rank
|
||||
if "AA_RANK" in tree[chunk].keys():
|
||||
for m in mode:
|
||||
if sev == None or tree[chunk]["AA_RANK"].get(m, -1) > sev:
|
||||
sev = tree[chunk]["AA_RANK"].get(m, None)
|
||||
return sev
|
||||
|
||||
|
||||
def handle_file(self, resource, mode):
|
||||
"""Returns the severity for the file, default value if no match found"""
|
||||
resource = resource[1:] # remove initial / from path
|
||||
|
@ -115,7 +115,7 @@ class Severity:
|
|||
return self.severity['DEFAULT_RANK']
|
||||
else:
|
||||
return sev
|
||||
|
||||
|
||||
def rank(self, resource, mode=None):
|
||||
"""Returns the rank for the resource file/capability"""
|
||||
if '@' in resource: # path contains variable
|
||||
|
@ -126,7 +126,7 @@ class Severity:
|
|||
return self.handle_capability(resource)
|
||||
else:
|
||||
raise AppArmorException("Unexpected rank input: %s" % resource)
|
||||
|
||||
|
||||
def handle_variable_rank(self, resource, mode):
|
||||
"""Returns the max possible rank for file resources containing variables"""
|
||||
regex_variable = re.compile('@{([^{.]*)}')
|
||||
|
@ -138,13 +138,13 @@ class Severity:
|
|||
for replacement in self.severity['VARIABLES'][variable]:
|
||||
resource_replaced = self.variable_replace(variable, replacement, resource)
|
||||
rank_new = self.handle_variable_rank(resource_replaced, mode)
|
||||
#rank_new = self.handle_variable_rank(resource.replace('@{'+variable+'}', replacement), mode)
|
||||
#rank_new = self.handle_variable_rank(resource.replace('@{'+variable+'}', replacement), mode)
|
||||
if rank == None or rank_new > rank:
|
||||
rank = rank_new
|
||||
return rank
|
||||
else:
|
||||
return self.handle_file(resource, mode)
|
||||
|
||||
|
||||
def variable_replace(self, variable, replacement, resource):
|
||||
"""Returns the expanded path for the passed variable"""
|
||||
leading = False
|
||||
|
@ -159,7 +159,7 @@ class Severity:
|
|||
if replacement[-1] == '/' and replacement[-2:] !='//' and trailing:
|
||||
replacement = replacement[:-1]
|
||||
return resource.replace(variable, replacement)
|
||||
|
||||
|
||||
def load_variables(self, prof_path):
|
||||
"""Loads the variables for the given profile"""
|
||||
regex_include = re.compile('^#?include\s*<(\S*)>')
|
||||
|
@ -172,7 +172,7 @@ class Severity:
|
|||
if match:
|
||||
new_path = match.groups()[0]
|
||||
new_path = self.PROF_DIR + '/' + new_path
|
||||
self.load_variables(new_path)
|
||||
self.load_variables(new_path)
|
||||
else:
|
||||
# Remove any comments
|
||||
if '#' in line:
|
||||
|
@ -190,7 +190,7 @@ class Severity:
|
|||
if line[0] in self.severity['VARIABLES'].keys():
|
||||
raise AppArmorException("Variable %s was previously declared in file: %s" % (line[0], prof_path))
|
||||
self.severity['VARIABLES'][line[0]] = [i.strip('"') for i in line[1].split()]
|
||||
|
||||
|
||||
def unload_variables(self):
|
||||
"""Clears all loaded variables"""
|
||||
self.severity['VARIABLES'] = dict()
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import sys
|
||||
|
||||
import apparmor.aa as apparmor
|
||||
|
||||
|
||||
class aa_tools:
|
||||
def __init__(self, tool_name, args):
|
||||
self.name = tool_name
|
||||
|
@ -21,22 +21,22 @@ class aa_tools:
|
|||
self.aa_mountpoint = apparmor.check_for_apparmor()
|
||||
elif tool_name == 'cleanprof':
|
||||
self.silent = args.silent
|
||||
|
||||
|
||||
def check_profile_dir(self):
|
||||
if self.profiledir:
|
||||
apparmor.profile_dir = apparmor.get_full_path(self.profiledir)
|
||||
if not os.path.isdir(apparmor.profile_dir):
|
||||
raise apparmor.AppArmorException("%s is not a directory." %self.profiledir)
|
||||
|
||||
|
||||
def check_disable_dir(self):
|
||||
if not os.path.isdir(self.disabledir):
|
||||
raise apparmor.AppArmorException("Can't find AppArmor disable directory %s." %self.disabledir)
|
||||
|
||||
|
||||
def act(self):
|
||||
for p in self.profiling:
|
||||
if not p:
|
||||
continue
|
||||
|
||||
|
||||
program = None
|
||||
if os.path.exists(p):
|
||||
program = apparmor.get_full_path(p).strip()
|
||||
|
@ -44,32 +44,32 @@ class aa_tools:
|
|||
which = apparmor.which(p)
|
||||
if which:
|
||||
program = apparmor.get_full_path(which)
|
||||
|
||||
|
||||
apparmor.read_profiles()
|
||||
#If program does not exists on the system but its profile does
|
||||
if not program and apparmor.profile_exists(p):
|
||||
program = p
|
||||
|
||||
|
||||
if not program or not(os.path.exists(program) or apparmor.profile_exists(program)):
|
||||
if program and not program.startswith('/'):
|
||||
program = apparmor.UI_GetString(_('The given program cannot be found, please try with the fully qualified path name of the program: '), '')
|
||||
else:
|
||||
apparmor.UI_Info(_("%s does not exist, please double-check the path.")%program)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if program and apparmor.profile_exists(program):#os.path.exists(program):
|
||||
if self.name == 'autodep':
|
||||
self.use_autodep(program)
|
||||
|
||||
|
||||
elif self.name == 'cleanprof':
|
||||
self.clean_profile(program, p)
|
||||
|
||||
|
||||
else:
|
||||
filename = apparmor.get_profile_filename(program)
|
||||
|
||||
|
||||
if not os.path.isfile(filename) or apparmor.is_skippable_file(filename):
|
||||
apparmor.UI_Info(_('Profile for %s not found, skipping')%p)
|
||||
|
||||
|
||||
elif self.name == 'disable':
|
||||
if not self.revert:
|
||||
apparmor.UI_Info(_('Disabling %s.')%program)
|
||||
|
@ -77,14 +77,14 @@ class aa_tools:
|
|||
else:
|
||||
apparmor.UI_Info(_('Enabling %s.')%program)
|
||||
self.enable_profile(filename)
|
||||
|
||||
|
||||
elif self.name == 'audit':
|
||||
if not self.remove:
|
||||
apparmor.UI_Info(_('Setting %s to audit mode.')%program)
|
||||
else:
|
||||
apparmor.UI_Info(_('Removing audit mode from %s.')%program)
|
||||
apparmor.change_profile_flags(filename, program, 'audit', not self.remove)
|
||||
|
||||
|
||||
elif self.name == 'complain':
|
||||
if not self.remove:
|
||||
apparmor.set_complain(filename, program)
|
||||
|
@ -94,20 +94,20 @@ class aa_tools:
|
|||
else:
|
||||
# One simply does not walk in here!
|
||||
raise apparmor.AppArmorException('Unknown tool: %s'%self.name)
|
||||
|
||||
|
||||
cmd_info = apparmor.cmd([apparmor.parser, filename, '-I%s'%apparmor.profile_dir, '-R 2>&1', '1>/dev/null'])
|
||||
#cmd_info = apparmor.cmd(['cat', filename, '|', apparmor.parser, '-I%s'%apparmor.profile_dir, '-R 2>&1', '1>/dev/null'])
|
||||
|
||||
|
||||
if cmd_info[0] != 0:
|
||||
raise apparmor.AppArmorException(cmd_info[1])
|
||||
|
||||
|
||||
else:
|
||||
if '/' not in p:
|
||||
apparmor.UI_Info(_("Can't find %s in the system path list. If the name of the application\nis correct, please run 'which %s' as a user with correct PATH\nenvironment set up in order to find the fully-qualified path and\nuse the full path as parameter.")%(p, p))
|
||||
else:
|
||||
apparmor.UI_Info(_("%s does not exist, please double-check the path.")%p)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def clean_profile(self, program, p):
|
||||
filename = apparmor.get_profile_filename(program)
|
||||
|
||||
|
@ -117,7 +117,7 @@ class aa_tools:
|
|||
deleted = cleanprof.remove_duplicate_rules(program)
|
||||
apparmor.UI_Info(_("\nDeleted %s rules.") % deleted)
|
||||
apparmor.changed[program] = True
|
||||
|
||||
|
||||
if filename:
|
||||
if not self.silent:
|
||||
q = apparmor.hasher()
|
||||
|
@ -145,19 +145,19 @@ class aa_tools:
|
|||
apparmor.reload_base(program)
|
||||
else:
|
||||
raise apparmor.AppArmorException(_('The profile for %s does not exists. Nothing to clean.')%p)
|
||||
|
||||
|
||||
def use_autodep(self, program):
|
||||
apparmor.check_qualifiers(program)
|
||||
|
||||
apparmor.check_qualifiers(program)
|
||||
|
||||
if os.path.exists(apparmor.get_profile_filename(program) and not self.force):
|
||||
apparmor.UI_Info('Profile for %s already exists - skipping.'%program)
|
||||
else:
|
||||
apparmor.autodep(program)
|
||||
if self.aa_mountpoint:
|
||||
apparmor.reload(program)
|
||||
|
||||
def enable_profile(self, filename):
|
||||
|
||||
def enable_profile(self, filename):
|
||||
apparmor.delete_symlink('disable', filename)
|
||||
|
||||
|
||||
def disable_profile(self, filename):
|
||||
apparmor.create_symlink('disable', filename)
|
|
@ -50,7 +50,7 @@ def get_translated_hotkey(translated, cmsg=''):
|
|||
if cmsg:
|
||||
raise AppArmorException(cmsg)
|
||||
else:
|
||||
raise AppArmorException('%s %s' %(msg, translated))
|
||||
raise AppArmorException('%s %s' %(msg, translated))
|
||||
|
||||
def UI_YesNo(text, default):
|
||||
debug_logger.debug('UI_YesNo: %s: %s %s' %(UI_mode, text, default))
|
||||
|
@ -78,7 +78,7 @@ def UI_YesNo(text, default):
|
|||
ans = 'n'
|
||||
else:
|
||||
ans = default
|
||||
|
||||
|
||||
else:
|
||||
SendDataToYast({
|
||||
'type': 'dialog-yesno',
|
||||
|
@ -98,11 +98,11 @@ def UI_YesNoCancel(text, default):
|
|||
yes = _('(Y)es')
|
||||
no = _('(N)o')
|
||||
cancel = _('(C)ancel')
|
||||
|
||||
|
||||
yeskey = get_translated_hotkey(yes).lower()
|
||||
nokey = get_translated_hotkey(no).lower()
|
||||
cancelkey = get_translated_hotkey(cancel).lower()
|
||||
|
||||
|
||||
ans = 'XXXINVALIDXXX'
|
||||
while ans not in ['c', 'n', 'y']:
|
||||
sys.stdout.write('\n' + text + '\n')
|
||||
|
@ -300,45 +300,45 @@ def Text_PromptUser(question):
|
|||
explanation = question['explanation']
|
||||
headers = question['headers']
|
||||
functions = question['functions']
|
||||
|
||||
|
||||
default = question['default']
|
||||
options = question['options']
|
||||
selected = question.get('selected', 0)
|
||||
helptext = question['helptext']
|
||||
if helptext:
|
||||
functions.append('CMD_HELP')
|
||||
|
||||
|
||||
menu_items = []
|
||||
keys = dict()
|
||||
|
||||
|
||||
for cmd in functions:
|
||||
if not CMDS.get(cmd, False):
|
||||
raise AppArmorException(_('PromptUser: Unknown command %s') % cmd)
|
||||
|
||||
|
||||
menutext = CMDS[cmd]
|
||||
|
||||
|
||||
key = get_translated_hotkey(menutext).lower()
|
||||
# Duplicate hotkey
|
||||
if keys.get(key, False):
|
||||
raise AppArmorException(_('PromptUser: Duplicate hotkey for %s: %s ') % (cmd, menutext))
|
||||
|
||||
if keys.get(key, False):
|
||||
raise AppArmorException(_('PromptUser: Duplicate hotkey for %s: %s ') % (cmd, menutext))
|
||||
|
||||
keys[key] = cmd
|
||||
|
||||
|
||||
if default and default == cmd:
|
||||
menutext = '[%s]' %menutext
|
||||
|
||||
|
||||
menu_items.append(menutext)
|
||||
|
||||
|
||||
default_key = 0
|
||||
if default and CMDS[default]:
|
||||
defaulttext = CMDS[default]
|
||||
defmsg = _('PromptUser: Invalid hotkey in default item')
|
||||
|
||||
|
||||
default_key = get_translated_hotkey(defaulttext, defmsg).lower()
|
||||
|
||||
if not keys.get(default_key, False):
|
||||
|
||||
if not keys.get(default_key, False):
|
||||
raise AppArmorException(_('PromptUser: Invalid default %s') % default)
|
||||
|
||||
|
||||
widest = 0
|
||||
header_copy = headers[:]
|
||||
while header_copy:
|
||||
|
@ -347,22 +347,22 @@ def Text_PromptUser(question):
|
|||
if len(header) > widest:
|
||||
widest = len(header)
|
||||
widest += 1
|
||||
|
||||
|
||||
formatstr = '%-' + str(widest) + 's %s\n'
|
||||
|
||||
|
||||
function_regexp = '^('
|
||||
function_regexp += '|'.join(keys.keys())
|
||||
if options:
|
||||
function_regexp += '|\d'
|
||||
function_regexp += ')$'
|
||||
|
||||
|
||||
ans = 'XXXINVALIDXXX'
|
||||
while not re.search(function_regexp, ans, flags=re.IGNORECASE):
|
||||
|
||||
|
||||
prompt = '\n'
|
||||
if title:
|
||||
prompt += '= %s =\n\n' %title
|
||||
|
||||
|
||||
if headers:
|
||||
header_copy = headers[:]
|
||||
while header_copy:
|
||||
|
@ -370,10 +370,10 @@ def Text_PromptUser(question):
|
|||
value = header_copy.pop(0)
|
||||
prompt += formatstr %(header+':', value)
|
||||
prompt += '\n'
|
||||
|
||||
|
||||
if explanation:
|
||||
prompt += explanation + '\n\n'
|
||||
|
||||
|
||||
if options:
|
||||
for index, option in enumerate(options):
|
||||
if selected == index:
|
||||
|
@ -382,45 +382,45 @@ def Text_PromptUser(question):
|
|||
format_option = ' %s - %s '
|
||||
prompt += format_option %(index+1, option)
|
||||
prompt += '\n'
|
||||
|
||||
|
||||
prompt += ' / '.join(menu_items)
|
||||
|
||||
|
||||
sys.stdout.write(prompt+'\n')
|
||||
|
||||
|
||||
ans = getkey().lower()
|
||||
|
||||
|
||||
if ans:
|
||||
if ans == 'up':
|
||||
if options and selected > 0:
|
||||
selected -= 1
|
||||
ans = 'XXXINVALIDXXX'
|
||||
|
||||
|
||||
elif ans == 'down':
|
||||
if options and selected < len(options)-1:
|
||||
selected += 1
|
||||
ans = 'XXXINVALIDXXX'
|
||||
|
||||
|
||||
# elif keys.get(ans, False) == 'CMD_HELP':
|
||||
# sys.stdout.write('\n%s\n' %helptext)
|
||||
# ans = 'XXXINVALIDXXX'
|
||||
|
||||
|
||||
elif is_number(ans) == 10:
|
||||
# If they hit return choose default option
|
||||
ans = default_key
|
||||
|
||||
|
||||
elif options and re.search('^\d$', ans):
|
||||
ans = int(ans)
|
||||
if ans > 0 and ans <= len(options):
|
||||
selected = ans - 1
|
||||
ans = 'XXXINVALIDXXX'
|
||||
|
||||
|
||||
if keys.get(ans, False) == 'CMD_HELP':
|
||||
sys.stdout.write('\n%s\n' %helptext)
|
||||
ans = 'again'
|
||||
|
||||
|
||||
if keys.get(ans, False):
|
||||
ans = keys[ans]
|
||||
|
||||
|
||||
return ans, selected
|
||||
|
||||
def is_number(number):
|
||||
|
@ -428,4 +428,3 @@ def is_number(number):
|
|||
return int(number)
|
||||
except:
|
||||
return False
|
||||
|
|
@ -11,7 +11,7 @@ debug_logger = DebugLogger('YaST')
|
|||
|
||||
def setup_yast():
|
||||
# To-Do
|
||||
pass
|
||||
pass
|
||||
|
||||
def shutdown_yast():
|
||||
# To-Do
|
||||
|
@ -30,7 +30,7 @@ def SendDataToYast(data):
|
|||
return True
|
||||
else:
|
||||
debug_logger.info('SendDataToYast: Expected \'Read\' but got-- %s' % line)
|
||||
error('SendDataToYast: didn\'t receive YCP command before connection died')
|
||||
error('SendDataToYast: didn\'t receive YCP command before connection died')
|
||||
|
||||
def GetDataFromYast():
|
||||
debug_logger.inf('GetDataFromYast: Waiting for YCP command')
|
||||
|
|
Loading…
Add table
Reference in a new issue