Hello,
Am Freitag, 5. September 2014 schrieb Kshitij Gupta:
> Seems I sent out that patch a bit early, a secondary consolidated
> patch which fixes (hopefully) the issue multiple profiles in a file is
> attached.
> (Brace a for loop is removed resulting in a huge diff due to the
> indent change).
As discussed in yesterday's meeting, we'd like to include this patch in
the 2.9 final release that is planned for this week (!)
I just updated the patch to apply on latest bzr[1] - the result is
attached as
mergeprof2-rebased.diff.
I'm also attaching
mergeprof2-rebased-diff-ignore-whitespace.diff
which is the same patch made with "diff -w" to ignore whitespace
changes. It's probably not a surprise that it's much shorter and easier
to read ;-)
That already gave me a mostly working aa-mergeprof, but I soon found out
why Kshitij said the patch is not final yet ;-)
I did the following additional fixes:
- remove some debug output (which Kshitij intentionally kept in the
draft patch)
- add a UI_Info to display which profile will be merged
- disable the mergeprofiles.clear_common() call because it crashes
- disable (M)ore (CMD_OTHER) because it crashes
- make (F)inish work everywhere
- change the help text so that it doesn't mention 3-way-merge until we
implement it
Those changes are in mergeprof-fixes.diff which applies on top of
mergeprof2-rebased.diff.
Remaining known issues I noticed while testing:
- aa-mergeprof always asks for includes, even if they are already there
- CMD_OTHER should work ;-)
Regards,
Christian Boltz
[1] actually I applied the patch against r2636, and then re-applied the
two commits after that
--
[IP-Adresse von ppp0 mit system() ermitteln]
Dazu Perl zu verwenden, ähnelt sicherlich ein wenig der Spatzenjagd
mit großkalibrigen Langrohrgeschützen...;-)
[Christian Schmidt in suse-linux]
=== modified file 'utils/aa-mergeprof'
--- utils/aa-mergeprof 2014-10-07 13:06:01 +0000
+++ utils/aa-mergeprof 2014-10-15 19:08:03 +0000
@@ -28,17 +28,17 @@
parser = argparse.ArgumentParser(description=_('Perform a 2-way or 3-way merge on the given profiles'),
epilog='WARNING: the arguments will change in a future version!')
-parser.add_argument('mine', type=str, help=_('your profile'))
-parser.add_argument('base', type=str, help=_('base profile'))
-parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
+parser.add_argument('files', nargs='+', type=str, help=_('base profile'))
+#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
#parser.add_argument('-a', '--auto', action='store_true', help=_('Automatically merge profiles, exits incase of *x conflicts'))
args = parser.parse_args()
+args.other = None
# 2-way merge or 3-way merge based on number of params
-merge_mode = 2 if args.other == None else 3
+merge_mode = 2 #if args.other == None else 3
-profiles = [args.mine, args.base, args.other]
+profiles = [args.files, [args.other]]
profiledir = args.dir
if profiledir:
@@ -46,25 +46,94 @@
if not os.path.isdir(apparmor.aa.profile_dir):
raise apparmor.AppArmorException(_("%s is not a directory.") %profiledir)
+def reset_aa():
+ apparmor.aa.aa = apparmor.aa.hasher()
+ apparmor.aa.filelist = apparmor.aa.hasher()
+ apparmor.aa.include = dict()
+ apparmor.aa.existing_profiles = apparmor.aa.hasher()
+ apparmor.aa.original_aa = apparmor.aa.hasher()
+
+def find_profiles_from_files(files):
+ profile_to_filename = dict()
+ for file_name in files:
+ apparmor.aa.read_profile(file_name, True)
+ for profile_name in apparmor.aa.filelist[file_name]['profiles'].keys():
+ profile_to_filename[profile_name] = file_name
+ reset_aa()
+
+ return profile_to_filename
+
+def find_files_from_profiles(profiles):
+ profile_to_filename = dict()
+ apparmor.aa.read_profiles()
+
+ for profile_name in profiles:
+ profile_to_filename[profile_name] = apparmor.aa.get_profile_filename(profile_name)
+
+ reset_aa()
+
+ return profile_to_filename
def main():
- mergeprofiles = Merge(profiles)
+ profiles_to_merge = set()
+
+ base_files, other_files = profiles
+
+ base_profile_to_file = find_profiles_from_files(base_files)
+
+ profiles_to_merge = profiles_to_merge.union(set(base_profile_to_file.keys()))
+
+ other_profile_to_file = dict()
+
+ if merge_mode == 3:
+ other_profile_to_file = find_profiles_from_files(other_files)
+ profiles_to_merge.add(other_profile_to_file.keys())
+
+ user_profile_to_file = find_files_from_profiles(profiles_to_merge)
+
+ print(base_files,"\n",other_files)
+ print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
+ print(profiles_to_merge)
+
+ for profile_name in profiles_to_merge:
+ user_file = user_profile_to_file[profile_name]
+ base_file = base_profile_to_file.get(profile_name, None)
+ other_file = None
+
+ if merge_mode == 3:
+ other_file = other_profile_to_file.get(profile_name, None)
+
+ if base_file == None:
+ if other_file == None:
+ continue
+
+ act([user_file, other_file, None], 2, profile_name)
+ else:
+ if other_file == None:
+ act([user_file, base_file, None], 2, profile_name)
+ else:
+ act([user_file, base_file, other_file], 3, profile_name)
+
+ reset_aa()
+
+def act(files, merge_mode, merging_profile):
+ mergeprofiles = Merge(files)
#Get rid of common/superfluous stuff
mergeprofiles.clear_common()
# if not args.auto:
if 1 == 1: # workaround to avoid lots of whitespace changes
if merge_mode == 3:
- mergeprofiles.ask_the_questions('other')
+ mergeprofiles.ask_the_questions('other', merging_profile)
mergeprofiles.clear_common()
- mergeprofiles.ask_the_questions('base')
+ mergeprofiles.ask_the_questions('base', merging_profile)
q = aaui.PromptQuestion()
q.title = _('Changed Local Profiles')
q.explanation = _('The following local profiles were changed. Would you like to save them?')
- q.functions = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT']
+ q.functions = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT', 'CMD_IGNORE_ENTRY']
q.default = 'CMD_VIEW_CHANGES'
q.options = []
q.selected = 0
@@ -84,6 +153,8 @@
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[program], program, '')
newprofile = apparmor.aa.serialize_profile(mergeprofiles.user.aa[program], program, '')
apparmor.aa.display_changes_with_comments(mergeprofiles.user.filename, newprofile)
+ elif ans == 'CMD_IGNORE_ENTRY':
+ break
class Merge(object):
@@ -94,25 +165,18 @@
apparmor.aa.read_profile(base, True)
self.base = cleanprofile.Prof(base)
- self.reset()
+ reset_aa()
#Read and parse other profile and save profile data, include data from it and reset them
if merge_mode == 3:
apparmor.aa.read_profile(other, True)
self.other = cleanprofile.Prof(other)
- self.reset()
+ reset_aa()
#Read and parse user profile
apparmor.aa.read_profile(user, True)
self.user = cleanprofile.Prof(user)
- def reset(self):
- apparmor.aa.aa = apparmor.aa.hasher()
- apparmor.aa.filelist = apparmor.aa.hasher()
- apparmor.aa.include = dict()
- apparmor.aa.existing_profiles = apparmor.aa.hasher()
- apparmor.aa.original_aa = apparmor.aa.hasher()
-
def clear_common(self):
deleted = 0
@@ -166,7 +230,7 @@
raise apparmor.aa.AppArmorException(_('Unknown selection'))
done = True
- def ask_the_questions(self, other):
+ def ask_the_questions(self, other, profile):
if other == 'other':
other = self.other
else:
@@ -199,501 +263,501 @@
sev_db = apparmor.aa.sev_db
if not sev_db:
sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
- for profile in sorted(other.aa.keys()):
- for hat in sorted(other.aa[profile].keys()):
- #Add the includes from the other profile to the user profile
- done = False
- options = list(map(lambda inc: '#include <%s>' %inc, sorted(other.aa[profile][hat]['include'].keys())))
- default_option = 1
-
- q = aaui.PromptQuestion()
- q.options = options
- q.selected = default_option - 1
- q.headers = [_('File includes'), _('Select the ones you wish to add')]
- q.functions = ['CMD_ALLOW', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
- q.default = 'CMD_ALLOW'
-
- while not done and options:
- ans, selected = q.promptUser()
- if ans == 'CMD_IGNORE_ENTRY':
- done = True
- elif ans == 'CMD_ALLOW':
- selection = options[selected]
- inc = apparmor.aa.re_match_include(selection)
- deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
- self.user.aa[profile][hat]['include'][inc] = True
- options.pop(selected)
- aaui.UI_Info(_('Adding %s to the file.') % selection)
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- #Add the capabilities
- for allow in ['allow', 'deny']:
- if other.aa[profile][hat].get(allow, False):
- continue
- for capability in sorted(other.aa[profile][hat][allow]['capability'].keys()):
- severity = sev_db.rank('CAP_%s' % capability)
+
+ for hat in sorted(other.aa[profile].keys()):
+ #Add the includes from the other profile to the user profile
+ done = False
+ options = list(map(lambda inc: '#include <%s>' %inc, sorted(other.aa[profile][hat]['include'].keys())))
+ default_option = 1
+
+ q = aaui.PromptQuestion()
+ q.options = options
+ q.selected = default_option - 1
+ q.headers = [_('File includes'), _('Select the ones you wish to add')]
+ q.functions = ['CMD_ALLOW', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
+ q.default = 'CMD_ALLOW'
+
+ while not done and options:
+ ans, selected = q.promptUser()
+ if ans == 'CMD_IGNORE_ENTRY':
+ done = True
+ elif ans == 'CMD_ALLOW':
+ selection = options[selected]
+ inc = apparmor.aa.re_match_include(selection)
+ deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
+ self.user.aa[profile][hat]['include'][inc] = True
+ options.pop(selected)
+ aaui.UI_Info(_('Adding %s to the file.') % selection)
+ if deleted:
+ aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+
+ #Add the capabilities
+ for allow in ['allow', 'deny']:
+ if other.aa[profile][hat].get(allow, False):
+ continue
+ for capability in sorted(other.aa[profile][hat][allow]['capability'].keys()):
+ severity = sev_db.rank('CAP_%s' % capability)
+ default_option = 1
+ options = []
+ newincludes = apparmor.aa.match_cap_includes(self.user.aa[profile][hat], capability)
+ q = aaui.PromptQuestion()
+ if newincludes:
+ options += list(map(lambda inc: '#include <%s>' %inc, sorted(set(newincludes))))
+
+ if options:
+ options.append('capability %s' % capability)
+ q.options = options
+ q.selected = default_option - 1
+
+ q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
+ q.headers += [_('Capability'), capability]
+ q.headers += [_('Severity'), severity]
+
+ audit_toggle = 0
+
+ q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
+
+ q.default = 'CMD_ALLOW'
+
+ done = False
+ while not done:
+ ans, selected = q.promptUser()
+ # Ignore the log entry
+ if ans == 'CMD_IGNORE_ENTRY':
+ done = True
+ break
+
+ if ans == 'CMD_ALLOW':
+ selection = ''
+ if options:
+ selection = options[selected]
+ match = apparmor.aa.re_match_include(selection)
+ if match:
+ deleted = False
+ inc = match
+ deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
+ self.user.aa[profile][hat]['include'][inc] = True
+
+ aaui.UI_Info(_('Adding %s to profile.') % selection)
+ if deleted:
+ aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+
+ self.user.aa[profile][hat]['allow']['capability'][capability]['set'] = True
+ self.user.aa[profile][hat]['allow']['capability'][capability]['audit'] = other.aa[profile][hat]['allow']['capability'][capability]['audit']
+
+ apparmor.aa.changed[profile] = True
+
+ aaui.UI_Info(_('Adding capability %s to profile.'), capability)
+ done = True
+
+ elif ans == 'CMD_DENY':
+ self.user.aa[profile][hat]['deny']['capability'][capability]['set'] = True
+ apparmor.aa.changed[profile] = True
+
+ aaui.UI_Info(_('Denying capability %s to profile.') % capability)
+ done = True
+ else:
+ done = False
+
+ # Process all the path entries.
+ for allow in ['allow', 'deny']:
+ for path in sorted(other.aa[profile][hat][allow]['path'].keys()):
+ #print(path, other.aa[profile][hat][allow]['path'][path])
+ mode = other.aa[profile][hat][allow]['path'][path]['mode']
+
+ if self.user.aa[profile][hat][allow]['path'].get(path, False):
+ mode = self.conflict_mode(profile, hat, allow, path, 'mode', other.aa[profile][hat][allow]['path'][path]['mode'], self.user.aa[profile][hat][allow]['path'][path]['mode'])
+ self.conflict_mode(profile, hat, allow, path, 'audit', other.aa[profile][hat][allow]['path'][path]['audit'], self.user.aa[profile][hat][allow]['path'][path]['audit'])
+ apparmor.aa.changed[profile] = True
+ continue
+ # Lookup modes from profile
+ allow_mode = set()
+ allow_audit = set()
+ deny_mode = set()
+ deny_audit = set()
+
+ fmode, famode, fm = apparmor.aa.rematchfrag(self.user.aa[profile][hat], 'allow', path)
+ if fmode:
+ allow_mode |= fmode
+ if famode:
+ allow_audit |= famode
+
+ cm, cam, m = apparmor.aa.rematchfrag(self.user.aa[profile][hat], 'deny', path)
+ if cm:
+ deny_mode |= cm
+ if cam:
+ deny_audit |= cam
+
+ imode, iamode, im = apparmor.aa.match_prof_incs_to_path(self.user.aa[profile][hat], 'allow', path)
+ if imode:
+ allow_mode |= imode
+ if iamode:
+ allow_audit |= iamode
+
+ cm, cam, m = apparmor.aa.match_prof_incs_to_path(self.user.aa[profile][hat], 'deny', path)
+ if cm:
+ deny_mode |= cm
+ if cam:
+ deny_audit |= cam
+
+ if deny_mode & apparmor.aamode.AA_MAY_EXEC:
+ deny_mode |= apparmor.aamode.ALL_AA_EXEC_TYPE
+
+ # Mask off the denied modes
+ mode = mode - deny_mode
+
+ # If we get an exec request from some kindof event that generates 'PERMITTING X'
+ # check if its already in allow_mode
+ # if not add ix permission
+ if mode & apparmor.aamode.AA_MAY_EXEC:
+ # Remove all type access permission
+ mode = mode - apparmor.aamode.ALL_AA_EXEC_TYPE
+ if not allow_mode & apparmor.aamode.AA_MAY_EXEC:
+ mode |= apparmor.aa.str_to_mode('ix')
+
+ # m is not implied by ix
+
+ ### If we get an mmap request, check if we already have it in allow_mode
+ ##if mode & AA_EXEC_MMAP:
+ ## # ix implies m, so we don't need to add m if ix is present
+ ## if contains(allow_mode, 'ix'):
+ ## mode = mode - AA_EXEC_MMAP
+
+ if not mode:
+ continue
+
+ matches = []
+
+ if fmode:
+ matches += fm
+
+ if imode:
+ matches += im
+
+ if not apparmor.aa.mode_contains(allow_mode, mode):
default_option = 1
options = []
- newincludes = apparmor.aa.match_cap_includes(self.user.aa[profile][hat], capability)
- q = aaui.PromptQuestion()
+ newincludes = []
+ include_valid = False
+
+ for incname in apparmor.aa.include.keys():
+ include_valid = False
+ # If already present skip
+ if self.user.aa[profile][hat][incname]:
+ continue
+ if incname.startswith(apparmor.aa.profile_dir):
+ incname = incname.replace(apparmor.aa.profile_dir+'/', '', 1)
+
+ include_valid = apparmor.aa.valid_include('', incname)
+
+ if not include_valid:
+ continue
+
+ cm, am, m = apparmor.aa.match_include_to_path(incname, 'allow', path)
+
+ if cm and apparmor.aa.mode_contains(cm, mode):
+ dm = apparmor.aa.match_include_to_path(incname, 'deny', path)[0]
+ # If the mode is denied
+ if not mode & dm:
+ if not list(filter(lambda s: '/**' == s, m)):
+ newincludes.append(incname)
+ # Add new includes to the options
if newincludes:
- options += list(map(lambda inc: '#include <%s>' %inc, sorted(set(newincludes))))
-
- if options:
- options.append('capability %s' % capability)
- q.options = options
- q.selected = default_option - 1
-
- q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
- q.headers += [_('Capability'), capability]
- q.headers += [_('Severity'), severity]
+ options += list(map(lambda s: '#include <%s>' % s, sorted(set(newincludes))))
+ # We should have literal the path in options list too
+ options.append(path)
+ # Add any the globs matching path from logprof
+ globs = apparmor.aa.glob_common(path)
+ if globs:
+ matches += globs
+ # Add any user entered matching globs
+ for user_glob in apparmor.aa.user_globs:
+ if apparmor.aa.matchliteral(user_glob, path):
+ matches.append(user_glob)
+
+ matches = list(set(matches))
+ if path in matches:
+ matches.remove(path)
+
+ options += apparmor.aa.order_globs(matches, path)
+ default_option = len(options)
+
+ sev_db.unload_variables()
+ sev_db.load_variables(apparmor.aa.get_profile_filename(profile))
+ severity = sev_db.rank(path, apparmor.aa.mode_to_str(mode))
+ sev_db.unload_variables()
audit_toggle = 0
-
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
-
- q.default = 'CMD_ALLOW'
-
+ owner_toggle = 0
+ if apparmor.aa.cfg['settings']['default_owner_prompt']:
+ owner_toggle = apparmor.aa.cfg['settings']['default_owner_prompt']
done = False
while not done:
+ q = aaui.PromptQuestion()
+ q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat),
+ _('Path'), path]
+
+ if allow_mode:
+ mode |= allow_mode
+ tail = ''
+ s = ''
+ prompt_mode = None
+ if owner_toggle == 0:
+ prompt_mode = apparmor.aa.flatten_mode(mode)
+ tail = ' ' + _('(owner permissions off)')
+ elif owner_toggle == 1:
+ prompt_mode = mode
+ elif owner_toggle == 2:
+ prompt_mode = allow_mode | apparmor.aa.owner_flatten_mode(mode - allow_mode)
+ tail = ' ' + _('(force new perms to owner)')
+ else:
+ prompt_mode = apparmor.aa.owner_flatten_mode(mode)
+ tail = ' ' + _('(force all rule perms to owner)')
+
+ if audit_toggle == 1:
+ s = apparmor.aa.mode_to_str_user(allow_mode)
+ if allow_mode:
+ s += ', '
+ s += 'audit ' + apparmor.aa.mode_to_str_user(prompt_mode - allow_mode) + tail
+ elif audit_toggle == 2:
+ s = 'audit ' + apparmor.aa.mode_to_str_user(prompt_mode) + tail
+ else:
+ s = apparmor.aa.mode_to_str_user(prompt_mode) + tail
+
+ q.headers += [_('Old Mode'), apparmor.aa.mode_to_str_user(allow_mode),
+ _('New Mode'), s]
+
+ else:
+ s = ''
+ tail = ''
+ prompt_mode = None
+ if audit_toggle:
+ s = 'audit'
+ if owner_toggle == 0:
+ prompt_mode = apparmor.aa.flatten_mode(mode)
+ tail = ' ' + _('(owner permissions off)')
+ elif owner_toggle == 1:
+ prompt_mode = mode
+ else:
+ prompt_mode = apparmor.aa.owner_flatten_mode(mode)
+ tail = ' ' + _('(force perms to owner)')
+
+ s = apparmor.aa.mode_to_str_user(prompt_mode)
+ q.headers += [_('Mode'), s]
+
+ q.headers += [_('Severity'), severity]
+ q.options = options
+ q.selected = default_option - 1
+ q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_GLOB',
+ 'CMD_GLOBEXT', 'CMD_NEW', 'CMD_ABORT',
+ 'CMD_FINISHED', 'CMD_OTHER']
+
+ q.default = 'CMD_ALLOW'
+
+
ans, selected = q.promptUser()
- # Ignore the log entry
+
if ans == 'CMD_IGNORE_ENTRY':
done = True
break
- if ans == 'CMD_ALLOW':
- selection = ''
- if options:
- selection = options[selected]
- match = apparmor.aa.re_match_include(selection)
+ if ans == 'CMD_OTHER':
+ audit_toggle, owner_toggle = aaui.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode)
+ elif ans == 'CMD_USER_TOGGLE':
+ owner_toggle += 1
+ if not allow_mode and owner_toggle == 2:
+ owner_toggle += 1
+ if owner_toggle > 3:
+ owner_toggle = 0
+ elif ans == 'CMD_ALLOW':
+ path = options[selected]
+ done = True
+ match = apparmor.aa.re_match_include(path)
if match:
- deleted = False
inc = match
+ deleted = 0
deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
- self.user.aa[profile][hat]['include'][inc] = True
-
- aaui.UI_Info(_('Adding %s to profile.') % selection)
+ self.user.aa[profile][hat]['include'][inc] = True
+ apparmor.aa.changed[profile] = True
+ aaui.UI_Info(_('Adding %s to profile.') % path)
if deleted:
aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
- self.user.aa[profile][hat]['allow']['capability'][capability]['set'] = True
- self.user.aa[profile][hat]['allow']['capability'][capability]['audit'] = other.aa[profile][hat]['allow']['capability'][capability]['audit']
-
- apparmor.aa.changed[profile] = True
-
- aaui.UI_Info(_('Adding capability %s to profile.'), capability)
- done = True
-
- elif ans == 'CMD_DENY':
- self.user.aa[profile][hat]['deny']['capability'][capability]['set'] = True
- apparmor.aa.changed[profile] = True
-
- aaui.UI_Info(_('Denying capability %s to profile.') % capability)
- done = True
- else:
- done = False
-
- # Process all the path entries.
- for allow in ['allow', 'deny']:
- for path in sorted(other.aa[profile][hat][allow]['path'].keys()):
- #print(path, other.aa[profile][hat][allow]['path'][path])
- mode = other.aa[profile][hat][allow]['path'][path]['mode']
-
- if self.user.aa[profile][hat][allow]['path'].get(path, False):
- mode = self.conflict_mode(profile, hat, allow, path, 'mode', other.aa[profile][hat][allow]['path'][path]['mode'], self.user.aa[profile][hat][allow]['path'][path]['mode'])
- self.conflict_mode(profile, hat, allow, path, 'audit', other.aa[profile][hat][allow]['path'][path]['audit'], self.user.aa[profile][hat][allow]['path'][path]['audit'])
- apparmor.aa.changed[profile] = True
- continue
- # Lookup modes from profile
- allow_mode = set()
- allow_audit = set()
- deny_mode = set()
- deny_audit = set()
-
- fmode, famode, fm = apparmor.aa.rematchfrag(self.user.aa[profile][hat], 'allow', path)
- if fmode:
- allow_mode |= fmode
- if famode:
- allow_audit |= famode
-
- cm, cam, m = apparmor.aa.rematchfrag(self.user.aa[profile][hat], 'deny', path)
- if cm:
- deny_mode |= cm
- if cam:
- deny_audit |= cam
-
- imode, iamode, im = apparmor.aa.match_prof_incs_to_path(self.user.aa[profile][hat], 'allow', path)
- if imode:
- allow_mode |= imode
- if iamode:
- allow_audit |= iamode
-
- cm, cam, m = apparmor.aa.match_prof_incs_to_path(self.user.aa[profile][hat], 'deny', path)
- if cm:
- deny_mode |= cm
- if cam:
- deny_audit |= cam
-
- if deny_mode & apparmor.aamode.AA_MAY_EXEC:
- deny_mode |= apparmor.aamode.ALL_AA_EXEC_TYPE
-
- # Mask off the denied modes
- mode = mode - deny_mode
-
- # If we get an exec request from some kindof event that generates 'PERMITTING X'
- # check if its already in allow_mode
- # if not add ix permission
- if mode & apparmor.aamode.AA_MAY_EXEC:
- # Remove all type access permission
- mode = mode - apparmor.aamode.ALL_AA_EXEC_TYPE
- if not allow_mode & apparmor.aamode.AA_MAY_EXEC:
- mode |= apparmor.aa.str_to_mode('ix')
-
- # m is not implied by ix
-
- ### If we get an mmap request, check if we already have it in allow_mode
- ##if mode & AA_EXEC_MMAP:
- ## # ix implies m, so we don't need to add m if ix is present
- ## if contains(allow_mode, 'ix'):
- ## mode = mode - AA_EXEC_MMAP
-
- if not mode:
- continue
-
- matches = []
-
- if fmode:
- matches += fm
-
- if imode:
- matches += im
-
- if not apparmor.aa.mode_contains(allow_mode, mode):
- default_option = 1
- options = []
- newincludes = []
- include_valid = False
-
- for incname in apparmor.aa.include.keys():
- include_valid = False
- # If already present skip
- if self.user.aa[profile][hat][incname]:
- continue
- if incname.startswith(apparmor.aa.profile_dir):
- incname = incname.replace(apparmor.aa.profile_dir+'/', '', 1)
-
- include_valid = apparmor.aa.valid_include('', incname)
-
- if not include_valid:
- continue
-
- cm, am, m = apparmor.aa.match_include_to_path(incname, 'allow', path)
-
- if cm and apparmor.aa.mode_contains(cm, mode):
- dm = apparmor.aa.match_include_to_path(incname, 'deny', path)[0]
- # If the mode is denied
- if not mode & dm:
- if not list(filter(lambda s: '/**' == s, m)):
- newincludes.append(incname)
- # Add new includes to the options
- if newincludes:
- options += list(map(lambda s: '#include <%s>' % s, sorted(set(newincludes))))
- # We should have literal the path in options list too
- options.append(path)
- # Add any the globs matching path from logprof
- globs = apparmor.aa.glob_common(path)
- if globs:
- matches += globs
- # Add any user entered matching globs
- for user_glob in apparmor.aa.user_globs:
- if apparmor.aa.matchliteral(user_glob, path):
- matches.append(user_glob)
-
- matches = list(set(matches))
- if path in matches:
- matches.remove(path)
-
- options += apparmor.aa.order_globs(matches, path)
- default_option = len(options)
-
- sev_db.unload_variables()
- sev_db.load_variables(apparmor.aa.get_profile_filename(profile))
- severity = sev_db.rank(path, apparmor.aa.mode_to_str(mode))
- sev_db.unload_variables()
-
- audit_toggle = 0
- owner_toggle = 0
- if apparmor.aa.cfg['settings']['default_owner_prompt']:
- owner_toggle = apparmor.aa.cfg['settings']['default_owner_prompt']
- done = False
- while not done:
- q = aaui.PromptQuestion()
- q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat),
- _('Path'), path]
-
- if allow_mode:
- mode |= allow_mode
- tail = ''
- s = ''
- prompt_mode = None
+ else:
+ if self.user.aa[profile][hat]['allow']['path'][path].get('mode', False):
+ mode |= self.user.aa[profile][hat]['allow']['path'][path]['mode']
+ deleted = []
+ for entry in self.user.aa[profile][hat]['allow']['path'].keys():
+ if path == entry:
+ continue
+
+ if apparmor.aa.matchregexp(path, entry):
+ if apparmor.aa.mode_contains(mode, self.user.aa[profile][hat]['allow']['path'][entry]['mode']):
+ deleted.append(entry)
+ for entry in deleted:
+ self.user.aa[profile][hat]['allow']['path'].pop(entry)
+ deleted = len(deleted)
+
if owner_toggle == 0:
- prompt_mode = apparmor.aa.flatten_mode(mode)
- tail = ' ' + _('(owner permissions off)')
- elif owner_toggle == 1:
- prompt_mode = mode
+ mode = apparmor.aa.flatten_mode(mode)
+ #elif owner_toggle == 1:
+ # mode = mode
elif owner_toggle == 2:
- prompt_mode = allow_mode | apparmor.aa.owner_flatten_mode(mode - allow_mode)
- tail = ' ' + _('(force new perms to owner)')
- else:
- prompt_mode = apparmor.aa.owner_flatten_mode(mode)
- tail = ' ' + _('(force all rule perms to owner)')
-
+ mode = allow_mode | apparmor.aa.owner_flatten_mode(mode - allow_mode)
+ elif owner_toggle == 3:
+ mode = apparmor.aa.owner_flatten_mode(mode)
+
+ if not self.user.aa[profile][hat]['allow'].get(path, False):
+ self.user.aa[profile][hat]['allow']['path'][path]['mode'] = self.user.aa[profile][hat]['allow']['path'][path].get('mode', set()) | mode
+
+
+ tmpmode = set()
if audit_toggle == 1:
- s = apparmor.aa.mode_to_str_user(allow_mode)
- if allow_mode:
- s += ', '
- s += 'audit ' + apparmor.aa.mode_to_str_user(prompt_mode - allow_mode) + tail
+ tmpmode = mode- allow_mode
elif audit_toggle == 2:
- s = 'audit ' + apparmor.aa.mode_to_str_user(prompt_mode) + tail
- else:
- s = apparmor.aa.mode_to_str_user(prompt_mode) + tail
-
- q.headers += [_('Old Mode'), apparmor.aa.mode_to_str_user(allow_mode),
- _('New Mode'), s]
-
- else:
- s = ''
- tail = ''
- prompt_mode = None
- if audit_toggle:
- s = 'audit'
- if owner_toggle == 0:
- prompt_mode = apparmor.aa.flatten_mode(mode)
- tail = ' ' + _('(owner permissions off)')
- elif owner_toggle == 1:
- prompt_mode = mode
- else:
- prompt_mode = apparmor.aa.owner_flatten_mode(mode)
- tail = ' ' + _('(force perms to owner)')
-
- s = apparmor.aa.mode_to_str_user(prompt_mode)
- q.headers += [_('Mode'), s]
-
- q.headers += [_('Severity'), severity]
- q.options = options
- q.selected = default_option - 1
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_GLOB',
- 'CMD_GLOBEXT', 'CMD_NEW', 'CMD_ABORT',
- 'CMD_FINISHED', 'CMD_OTHER']
-
- q.default = 'CMD_ALLOW'
-
-
- ans, selected = q.promptUser()
-
- if ans == 'CMD_IGNORE_ENTRY':
- done = True
- break
-
- if ans == 'CMD_OTHER':
- audit_toggle, owner_toggle = aaui.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode)
- elif ans == 'CMD_USER_TOGGLE':
- owner_toggle += 1
- if not allow_mode and owner_toggle == 2:
- owner_toggle += 1
- if owner_toggle > 3:
- owner_toggle = 0
- elif ans == 'CMD_ALLOW':
- path = options[selected]
- done = True
- match = apparmor.aa.re_match_include(path)
- if match:
- inc = match
- deleted = 0
- deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
- self.user.aa[profile][hat]['include'][inc] = True
- apparmor.aa.changed[profile] = True
- aaui.UI_Info(_('Adding %s to profile.') % path)
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- else:
- if self.user.aa[profile][hat]['allow']['path'][path].get('mode', False):
- mode |= self.user.aa[profile][hat]['allow']['path'][path]['mode']
- deleted = []
- for entry in self.user.aa[profile][hat]['allow']['path'].keys():
- if path == entry:
- continue
-
- if apparmor.aa.matchregexp(path, entry):
- if apparmor.aa.mode_contains(mode, self.user.aa[profile][hat]['allow']['path'][entry]['mode']):
- deleted.append(entry)
- for entry in deleted:
- self.user.aa[profile][hat]['allow']['path'].pop(entry)
- deleted = len(deleted)
-
- if owner_toggle == 0:
- mode = apparmor.aa.flatten_mode(mode)
- #elif owner_toggle == 1:
- # mode = mode
- elif owner_toggle == 2:
- mode = allow_mode | apparmor.aa.owner_flatten_mode(mode - allow_mode)
- elif owner_toggle == 3:
- mode = apparmor.aa.owner_flatten_mode(mode)
-
- if not self.user.aa[profile][hat]['allow'].get(path, False):
- self.user.aa[profile][hat]['allow']['path'][path]['mode'] = self.user.aa[profile][hat]['allow']['path'][path].get('mode', set()) | mode
-
-
- tmpmode = set()
- if audit_toggle == 1:
- tmpmode = mode- allow_mode
- elif audit_toggle == 2:
- tmpmode = mode
-
- self.user.aa[profile][hat]['allow']['path'][path]['audit'] = self.user.aa[profile][hat]['allow']['path'][path].get('audit', set()) | tmpmode
-
- apparmor.aa.changed[profile] = True
-
- aaui.UI_Info(_('Adding %(path)s %(mode)s to profile') % { 'path': path, 'mode': apparmor.aa.mode_to_str_user(mode) })
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- elif ans == 'CMD_DENY':
- path = options[selected].strip()
- # Add new entry?
- self.user.aa[profile][hat]['deny']['path'][path]['mode'] = self.user.aa[profile][hat]['deny']['path'][path].get('mode', set()) | (mode - allow_mode)
-
- self.user.aa[profile][hat]['deny']['path'][path]['audit'] = self.user.aa[profile][hat]['deny']['path'][path].get('audit', set())
+ tmpmode = mode
+
+ self.user.aa[profile][hat]['allow']['path'][path]['audit'] = self.user.aa[profile][hat]['allow']['path'][path].get('audit', set()) | tmpmode
apparmor.aa.changed[profile] = True
- done = True
-
- elif ans == 'CMD_NEW':
- arg = options[selected]
- if not apparmor.aa.re_match_include(arg):
- ans = aaui.UI_GetString(_('Enter new path: '), arg)
+ aaui.UI_Info(_('Adding %(path)s %(mode)s to profile') % { 'path': path, 'mode': apparmor.aa.mode_to_str_user(mode) })
+ if deleted:
+ aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+
+ elif ans == 'CMD_DENY':
+ path = options[selected].strip()
+ # Add new entry?
+ self.user.aa[profile][hat]['deny']['path'][path]['mode'] = self.user.aa[profile][hat]['deny']['path'][path].get('mode', set()) | (mode - allow_mode)
+
+ self.user.aa[profile][hat]['deny']['path'][path]['audit'] = self.user.aa[profile][hat]['deny']['path'][path].get('audit', set())
+
+ apparmor.aa.changed[profile] = True
+
+ done = True
+
+ elif ans == 'CMD_NEW':
+ arg = options[selected]
+ if not apparmor.aa.re_match_include(arg):
+ ans = aaui.UI_GetString(_('Enter new path: '), arg)
# if ans:
# if not matchliteral(ans, path):
# ynprompt = _('The specified path does not match this log entry:\n\n Log Entry: %s\n Entered Path: %s\nDo you really want to use this path?') % (path,ans)
# key = aaui.UI_YesNo(ynprompt, 'n')
# if key == 'n':
# continue
- apparmor.aa.user_globs.append(ans)
- options.append(ans)
- default_option = len(options)
-
- elif ans == 'CMD_GLOB':
- newpath = options[selected].strip()
- if not apparmor.aa.re_match_include(newpath):
- newpath = apparmor.aa.glob_path(newpath)
-
- if newpath not in options:
- options.append(newpath)
- default_option = len(options)
- else:
- default_option = options.index(newpath) + 1
-
- elif ans == 'CMD_GLOBEXT':
- newpath = options[selected].strip()
- if not apparmor.aa.re_match_include(newpath):
- newpath = apparmor.aa.glob_path_withext(newpath)
-
- if newpath not in options:
- options.append(newpath)
- default_option = len(options)
- else:
- default_option = options.index(newpath) + 1
-
- elif re.search('\d', ans):
- default_option = ans
-
- #
- for allow in ['allow', 'deny']:
- for family in sorted(other.aa[profile][hat][allow]['netdomain']['rule'].keys()):
- # severity handling for net toggles goes here
-
- for sock_type in sorted(other.aa[profile][hat][allow]['netdomain']['rule'][family].keys()):
- if apparmor.aa.profile_known_network(self.user.aa[profile][hat], family, sock_type):
- continue
- default_option = 1
- options = []
- newincludes = apparmor.aa.match_net_includes(self.user.aa[profile][hat], family, sock_type)
- q = aaui.PromptQuestion()
- if newincludes:
- options += list(map(lambda s: '#include <%s>'%s, sorted(set(newincludes))))
- if True:#options:
- options.append('network %s %s' % (family, sock_type))
- q.options = options
- q.selected = default_option - 1
-
- q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
- q.headers += [_('Network Family'), family]
- q.headers += [_('Socket Type'), sock_type]
-
- audit_toggle = 0
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_AUDIT_NEW',
- 'CMD_ABORT', 'CMD_FINISHED']
-
- q.default = 'CMD_ALLOW'
-
- done = False
- while not done:
- ans, selected = q.promptUser()
- if ans == 'CMD_IGNORE_ENTRY':
- done = True
- break
-
- if ans.startswith('CMD_AUDIT'):
- audit_toggle = not audit_toggle
- audit = ''
- if audit_toggle:
- audit = 'audit'
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_AUDIT_OFF',
- 'CMD_ABORT', 'CMD_FINISHED']
- else:
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_AUDIT_NEW',
- 'CMD_ABORT', 'CMD_FINISHED']
- q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
- q.headers += [_('Network Family'), audit + family]
- q.headers += [_('Socket Type'), sock_type]
-
- elif ans == 'CMD_ALLOW':
- #print(options, selected)
- selection = options[selected]
- done = True
- if apparmor.aa.re_match_include(selection): #re.search('#include\s+<.+>$', selection):
- inc = apparmor.aa.re_match_include(selection) #re.search('#include\s+<(.+)>$', selection).groups()[0]
- deleted = 0
- deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
-
- self.user.aa[profile][hat]['include'][inc] = True
-
- apparmor.aa.changed[profile] = True
-
- aaui.UI_Info(_('Adding %s to profile') % selection)
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- else:
- self.user.aa[profile][hat]['allow']['netdomain']['audit'][family][sock_type] = audit_toggle
- self.user.aa[profile][hat]['allow']['netdomain']['rule'][family][sock_type] = True
-
- apparmor.aa.changed[profile] = True
-
- aaui.UI_Info(_('Adding network access %(family)s %(type)s to profile.') % { 'family': family, 'type': sock_type })
-
- elif ans == 'CMD_DENY':
- done = True
- self.user.aa[profile][hat]['deny']['netdomain']['rule'][family][sock_type] = True
- apparmor.aa.changed[profile] = True
- aaui.UI_Info(_('Denying network access %(family)s %(type)s to profile') % { 'family': family, 'type': sock_type })
-
- else:
- done = False
+ apparmor.aa.user_globs.append(ans)
+ options.append(ans)
+ default_option = len(options)
+
+ elif ans == 'CMD_GLOB':
+ newpath = options[selected].strip()
+ if not apparmor.aa.re_match_include(newpath):
+ newpath = apparmor.aa.glob_path(newpath)
+
+ if newpath not in options:
+ options.append(newpath)
+ default_option = len(options)
+ else:
+ default_option = options.index(newpath) + 1
+
+ elif ans == 'CMD_GLOBEXT':
+ newpath = options[selected].strip()
+ if not apparmor.aa.re_match_include(newpath):
+ newpath = apparmor.aa.glob_path_withext(newpath)
+
+ if newpath not in options:
+ options.append(newpath)
+ default_option = len(options)
+ else:
+ default_option = options.index(newpath) + 1
+
+ elif re.search('\d', ans):
+ default_option = ans
+
+ #
+ for allow in ['allow', 'deny']:
+ for family in sorted(other.aa[profile][hat][allow]['netdomain']['rule'].keys()):
+ # severity handling for net toggles goes here
+
+ for sock_type in sorted(other.aa[profile][hat][allow]['netdomain']['rule'][family].keys()):
+ if apparmor.aa.profile_known_network(self.user.aa[profile][hat], family, sock_type):
+ continue
+ default_option = 1
+ options = []
+ newincludes = apparmor.aa.match_net_includes(self.user.aa[profile][hat], family, sock_type)
+ q = aaui.PromptQuestion()
+ if newincludes:
+ options += list(map(lambda s: '#include <%s>'%s, sorted(set(newincludes))))
+ if True:#options:
+ options.append('network %s %s' % (family, sock_type))
+ q.options = options
+ q.selected = default_option - 1
+
+ q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
+ q.headers += [_('Network Family'), family]
+ q.headers += [_('Socket Type'), sock_type]
+
+ audit_toggle = 0
+ q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_AUDIT_NEW',
+ 'CMD_ABORT', 'CMD_FINISHED']
+
+ q.default = 'CMD_ALLOW'
+
+ done = False
+ while not done:
+ ans, selected = q.promptUser()
+ if ans == 'CMD_IGNORE_ENTRY':
+ done = True
+ break
+
+ if ans.startswith('CMD_AUDIT'):
+ audit_toggle = not audit_toggle
+ audit = ''
+ if audit_toggle:
+ audit = 'audit'
+ q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_AUDIT_OFF',
+ 'CMD_ABORT', 'CMD_FINISHED']
+ else:
+ q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_AUDIT_NEW',
+ 'CMD_ABORT', 'CMD_FINISHED']
+ q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
+ q.headers += [_('Network Family'), audit + family]
+ q.headers += [_('Socket Type'), sock_type]
+
+ elif ans == 'CMD_ALLOW':
+ #print(options, selected)
+ selection = options[selected]
+ done = True
+ if apparmor.aa.re_match_include(selection): #re.search('#include\s+<.+>$', selection):
+ inc = apparmor.aa.re_match_include(selection) #re.search('#include\s+<(.+)>$', selection).groups()[0]
+ deleted = 0
+ deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
+
+ self.user.aa[profile][hat]['include'][inc] = True
+
+ apparmor.aa.changed[profile] = True
+
+ aaui.UI_Info(_('Adding %s to profile') % selection)
+ if deleted:
+ aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+
+ else:
+ self.user.aa[profile][hat]['allow']['netdomain']['audit'][family][sock_type] = audit_toggle
+ self.user.aa[profile][hat]['allow']['netdomain']['rule'][family][sock_type] = True
+
+ apparmor.aa.changed[profile] = True
+
+ aaui.UI_Info(_('Adding network access %(family)s %(type)s to profile.') % { 'family': family, 'type': sock_type })
+
+ elif ans == 'CMD_DENY':
+ done = True
+ self.user.aa[profile][hat]['deny']['netdomain']['rule'][family][sock_type] = True
+ apparmor.aa.changed[profile] = True
+ aaui.UI_Info(_('Denying network access %(family)s %(type)s to profile') % { 'family': family, 'type': sock_type })
+
+ else:
+ done = False
if __name__ == '__main__':
main()
--- aa-mergeprof 2014-10-15 22:02:03.608738000 +0200
+++ aa-mergeprof__MERGED 2014-10-15 21:08:12.610435497 +0200
@@ -28,17 +28,17 @@ _ = init_translation()
parser = argparse.ArgumentParser(description=_('Perform a 2-way or 3-way merge on the given profiles'),
epilog='WARNING: the arguments will change in a future version!')
-parser.add_argument('mine', type=str, help=_('your profile'))
-parser.add_argument('base', type=str, help=_('base profile'))
-parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
+parser.add_argument('files', nargs='+', type=str, help=_('base profile'))
+#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
#parser.add_argument('-a', '--auto', action='store_true', help=_('Automatically merge profiles, exits incase of *x conflicts'))
args = parser.parse_args()
+args.other = None
# 2-way merge or 3-way merge based on number of params
-merge_mode = 2 if args.other == None else 3
+merge_mode = 2 #if args.other == None else 3
-profiles = [args.mine, args.base, args.other]
+profiles = [args.files, [args.other]]
profiledir = args.dir
if profiledir:
@@ -46,25 +46,94 @@ if profiledir:
if not os.path.isdir(apparmor.aa.profile_dir):
raise apparmor.AppArmorException(_("%s is not a directory.") %profiledir)
+def reset_aa():
+ apparmor.aa.aa = apparmor.aa.hasher()
+ apparmor.aa.filelist = apparmor.aa.hasher()
+ apparmor.aa.include = dict()
+ apparmor.aa.existing_profiles = apparmor.aa.hasher()
+ apparmor.aa.original_aa = apparmor.aa.hasher()
+
+def find_profiles_from_files(files):
+ profile_to_filename = dict()
+ for file_name in files:
+ apparmor.aa.read_profile(file_name, True)
+ for profile_name in apparmor.aa.filelist[file_name]['profiles'].keys():
+ profile_to_filename[profile_name] = file_name
+ reset_aa()
+
+ return profile_to_filename
+
+def find_files_from_profiles(profiles):
+ profile_to_filename = dict()
+ apparmor.aa.read_profiles()
+
+ for profile_name in profiles:
+ profile_to_filename[profile_name] = apparmor.aa.get_profile_filename(profile_name)
+
+ reset_aa()
+
+ return profile_to_filename
def main():
- mergeprofiles = Merge(profiles)
+ profiles_to_merge = set()
+
+ base_files, other_files = profiles
+
+ base_profile_to_file = find_profiles_from_files(base_files)
+
+ profiles_to_merge = profiles_to_merge.union(set(base_profile_to_file.keys()))
+
+ other_profile_to_file = dict()
+
+ if merge_mode == 3:
+ other_profile_to_file = find_profiles_from_files(other_files)
+ profiles_to_merge.add(other_profile_to_file.keys())
+
+ user_profile_to_file = find_files_from_profiles(profiles_to_merge)
+
+ print(base_files,"\n",other_files)
+ print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
+ print(profiles_to_merge)
+
+ for profile_name in profiles_to_merge:
+ user_file = user_profile_to_file[profile_name]
+ base_file = base_profile_to_file.get(profile_name, None)
+ other_file = None
+
+ if merge_mode == 3:
+ other_file = other_profile_to_file.get(profile_name, None)
+
+ if base_file == None:
+ if other_file == None:
+ continue
+
+ act([user_file, other_file, None], 2, profile_name)
+ else:
+ if other_file == None:
+ act([user_file, base_file, None], 2, profile_name)
+ else:
+ act([user_file, base_file, other_file], 3, profile_name)
+
+ reset_aa()
+
+def act(files, merge_mode, merging_profile):
+ mergeprofiles = Merge(files)
#Get rid of common/superfluous stuff
mergeprofiles.clear_common()
# if not args.auto:
if 1 == 1: # workaround to avoid lots of whitespace changes
if merge_mode == 3:
- mergeprofiles.ask_the_questions('other')
+ mergeprofiles.ask_the_questions('other', merging_profile)
mergeprofiles.clear_common()
- mergeprofiles.ask_the_questions('base')
+ mergeprofiles.ask_the_questions('base', merging_profile)
q = aaui.PromptQuestion()
q.title = _('Changed Local Profiles')
q.explanation = _('The following local profiles were changed. Would you like to save them?')
- q.functions = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT']
+ q.functions = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT', 'CMD_IGNORE_ENTRY']
q.default = 'CMD_VIEW_CHANGES'
q.options = []
q.selected = 0
@@ -84,6 +153,8 @@ def main():
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[program], program, '')
newprofile = apparmor.aa.serialize_profile(mergeprofiles.user.aa[program], program, '')
apparmor.aa.display_changes_with_comments(mergeprofiles.user.filename, newprofile)
+ elif ans == 'CMD_IGNORE_ENTRY':
+ break
class Merge(object):
@@ -94,25 +165,18 @@ class Merge(object):
apparmor.aa.read_profile(base, True)
self.base = cleanprofile.Prof(base)
- self.reset()
+ reset_aa()
#Read and parse other profile and save profile data, include data from it and reset them
if merge_mode == 3:
apparmor.aa.read_profile(other, True)
self.other = cleanprofile.Prof(other)
- self.reset()
+ reset_aa()
#Read and parse user profile
apparmor.aa.read_profile(user, True)
self.user = cleanprofile.Prof(user)
- def reset(self):
- apparmor.aa.aa = apparmor.aa.hasher()
- apparmor.aa.filelist = apparmor.aa.hasher()
- apparmor.aa.include = dict()
- apparmor.aa.existing_profiles = apparmor.aa.hasher()
- apparmor.aa.original_aa = apparmor.aa.hasher()
-
def clear_common(self):
deleted = 0
@@ -166,7 +230,7 @@ class Merge(object):
raise apparmor.aa.AppArmorException(_('Unknown selection'))
done = True
- def ask_the_questions(self, other):
+ def ask_the_questions(self, other, profile):
if other == 'other':
other = self.other
else:
@@ -199,7 +263,7 @@ class Merge(object):
sev_db = apparmor.aa.sev_db
if not sev_db:
sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
- for profile in sorted(other.aa.keys()):
+
for hat in sorted(other.aa[profile].keys()):
#Add the includes from the other profile to the user profile
done = False
--- aa-mergeprof__MERGED 2014-10-15 21:08:12.610435497 +0200
+++ aa-mergeprof 2014-10-15 22:08:18.942940939 +0200
@@ -26,8 +26,7 @@ import apparmor.ui as aaui
from apparmor.translations import init_translation
_ = init_translation()
-parser = argparse.ArgumentParser(description=_('Perform a 2-way or 3-way merge on the given profiles'),
- epilog='WARNING: the arguments will change in a future version!')
+parser = argparse.ArgumentParser(description=_('Merge the given profiles into /etc/apparmor.d/ (or the directory specified with -d)'))
parser.add_argument('files', nargs='+', type=str, help=_('base profile'))
#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
@@ -91,11 +90,12 @@ def main():
user_profile_to_file = find_files_from_profiles(profiles_to_merge)
- print(base_files,"\n",other_files)
- print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
- print(profiles_to_merge)
+# print(base_files,"\n",other_files)
+# print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
+# print(profiles_to_merge)
for profile_name in profiles_to_merge:
+ aaui.UI_Info("\n\n" + _("Merging profile for %s" % profile_name))
user_file = user_profile_to_file[profile_name]
base_file = base_profile_to_file.get(profile_name, None)
other_file = None
@@ -119,7 +119,26 @@ def main():
def act(files, merge_mode, merging_profile):
mergeprofiles = Merge(files)
#Get rid of common/superfluous stuff
- mergeprofiles.clear_common()
+# mergeprofiles.clear_common()
+# temporarily disabled because...
+
+# Traceback (most recent call last):
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/aa-mergeprof", line 764, in <module>
+# main()
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/aa-mergeprof", line 114, in main
+# act([user_file, base_file, None], 2, profile_name)
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/aa-mergeprof", line 123, in act
+# mergeprofiles.clear_common()
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/aa-mergeprof", line 191, in clear_common
+# deleted += user_base.compare_profiles()
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/cleanprofile.py", line 42, in compare_profiles
+# deleted += self.remove_duplicate_rules(profile)
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/cleanprofile.py", line 72, in remove_duplicate_rules
+# deleted += delete_path_duplicates(self.profile.aa[program][hat], self.other.aa[program][hat], 'allow', self.same_file)
+# File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/cleanprofile.py", line 107, in delete_path_duplicates
+# profile_other[allow]['path'].pop(entry)
+# KeyError: '/etc/postfix/ssl/certs/cboltz-key.pem'
+
# if not args.auto:
if 1 == 1: # workaround to avoid lots of whitespace changes
@@ -250,7 +269,7 @@ class Merge(object):
q.default = 'CMD_ALLOW'
while not done and options:
- ans, selected = q.PromptUser()
+ ans, selected = q.promptUser()
if ans == 'CMD_IGNORE_ENTRY':
done = True
elif ans == 'CMD_ALLOW':
@@ -259,6 +278,8 @@ class Merge(object):
self.user.filelist[self.user.filename]['include'][inc] = True
options.pop(selected)
aaui.UI_Info(_('Adding %s to the file.') % selection)
+ elif ans == 'CMD_FINISHED':
+ return
sev_db = apparmor.aa.sev_db
if not sev_db:
@@ -290,6 +311,8 @@ class Merge(object):
aaui.UI_Info(_('Adding %s to the file.') % selection)
if deleted:
aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+ elif ans == 'CMD_FINISHED':
+ return
#Add the capabilities
for allow in ['allow', 'deny']:
@@ -327,6 +350,9 @@ class Merge(object):
done = True
break
+ elif ans == 'CMD_FINISHED':
+ return
+
if ans == 'CMD_ALLOW':
selection = ''
if options:
@@ -561,8 +587,15 @@ class Merge(object):
done = True
break
+ elif ans == 'CMD_FINISHED':
+ return
+
if ans == 'CMD_OTHER':
- audit_toggle, owner_toggle = aaui.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode)
+ aaui.UI_Important("Sorry, not implemented yet!")
+ # audit_toggle, owner_toggle = aaui.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode)
+# crashes with
+# audit_toggle, owner_toggle = aaui.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode)
+# AttributeError: 'module' object has no attribute 'UI_ask_mode_toggles'
elif ans == 'CMD_USER_TOGGLE':
owner_toggle += 1
if not allow_mode and owner_toggle == 2:
@@ -711,6 +744,9 @@ class Merge(object):
done = True
break
+ elif ans == 'CMD_FINISHED':
+ return
+
if ans.startswith('CMD_AUDIT'):
audit_toggle = not audit_toggle
audit = ''
--
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at:
https://lists.ubuntu.com/mailman/listinfo/apparmor