2016-10-01 20:57:09 +02:00
#! /usr/bin/python3
2013-09-28 20:43:06 +05:30
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
2016-05-10 14:32:46 +02:00
# Copyright (C) 2014-2016 Christian Boltz <apparmor@cboltz.de>
2013-09-28 20:43:06 +05:30
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# ----------------------------------------------------------------------
2013-09-12 14:42:15 +05:30
import argparse
2014-08-04 20:19:08 +02:00
import os
2013-09-12 14:42:15 +05:30
2013-09-23 19:32:25 +05:30
import apparmor.aa
import apparmor.aamode
2016-06-10 01:18:32 +05:30
2013-09-23 19:32:25 +05:30
import apparmor.severity
2013-09-17 22:30:48 +05:30
import apparmor.cleanprofile as cleanprofile
2014-07-28 00:24:26 +02:00
import apparmor.ui as aaui
2013-09-19 10:32:19 +05:30
2016-10-01 19:58:40 +02:00
from apparmor.aa import (add_to_options, available_buttons, combine_name, delete_duplicates,
[41/38] let aa-mergeprof ask about new hats and subprofiles
If a merged profile contains additional hats or subprofiles, the "old"
aa-mergeprof silently created them as additional hasher elements (partly
buggy, because subprofiles would end up as '^/subprofile' instead of
'profile /subprofile'). After switching to FileRule, aa-mergeprof crashes
on new hats or subprofiles.
This patch adds code to ask the user if the new hat or subprofile should
be added - which means this patch replaces two bugs (crash + silently
adding subprofiles and hats) with a new feature ;-)
The new questions also add a new text CMD_ADDSUBPROFILE in ui.py.
Finally, the new "button" combinations get added to test-translations.py.
If you want to test, try to aa-mergeprof this profile (the subprofile
and hat are dummies, nothing ping would really require):
#include <tunables/global>
/{usr/,}bin/ping {
#include <abstractions/base>
#include <abstractions/consoles>
#include <abstractions/nameservice>
capability net_raw,
capability setuid,
network inet raw,
network inet6 raw,
/{,usr/}bin/ping mixr,
/etc/modules.conf r,
^hat {
/bin/hat r,
/bin/bash px,
}
profile /subprofile {
/bin/subprofile r,
/bin/bash px,
}
# Site-specific additions and overrides. See local/README for details.
#include <local/bin.ping>
}
Note that this patch is not covered by unittests, but it passed all my
manual tests.
Acked-by: Steve Beattie <steve@nxnw.org>
Bug: https://launchpad.net/bugs/1507469
2016-10-01 20:21:06 +02:00
get_profile_filename, is_known_rule, match_includes, profile_storage,
2016-10-01 20:05:27 +02:00
set_options_audit_mode, propose_file_rules, selection_to_rule_obj)
2016-10-01 20:04:42 +02:00
from apparmor.aare import AARE
2016-06-10 01:18:32 +05:30
from apparmor.common import AppArmorException
from apparmor.regex import re_match_include
2015-07-06 22:02:34 +02:00
# setup exception handling
from apparmor.fail import enable_aa_exception_handler
enable_aa_exception_handler()
2014-02-10 22:15:05 -08:00
# setup module translations
2014-02-11 16:23:21 -08:00
from apparmor.translations import init_translation
_ = init_translation()
2014-02-10 22:15:05 -08:00
2014-10-16 23:25:33 +02:00
parser = argparse.ArgumentParser(description=_('Merge the given profiles into /etc/apparmor.d/ (or the directory specified with -d)'))
2014-10-16 23:35:06 +02:00
parser.add_argument('files', nargs='+', type=str, help=_('Profile(s) to merge'))
2014-10-16 20:06:45 +02:00
#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
2013-09-22 15:25:20 +05:30
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
2014-09-04 01:49:47 +02:00
#parser.add_argument('-a', '--auto', action='store_true', help=_('Automatically merge profiles, exits incase of *x conflicts'))
2013-09-12 14:42:15 +05:30
args = parser.parse_args()
2014-10-16 20:06:45 +02:00
args.other = None
2014-07-29 12:39:12 +02:00
# 2-way merge or 3-way merge based on number of params
2014-10-16 20:06:45 +02:00
merge_mode = 2 #if args.other == None else 3
2013-09-12 14:42:15 +05:30
2014-10-16 20:06:45 +02:00
profiles = [args.files, [args.other]]
2014-02-13 08:31:59 -08:00
2014-08-04 20:19:08 +02:00
profiledir = args.dir
if profiledir:
apparmor.aa.profile_dir = apparmor.aa.get_full_path(profiledir)
if not os.path.isdir(apparmor.aa.profile_dir):
2015-05-18 01:35:51 +02:00
raise AppArmorException(_("%s is not a directory.") %profiledir)
2014-08-04 20:19:08 +02:00
2014-10-16 20:06:45 +02:00
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
2014-08-04 20:19:08 +02:00
2013-09-12 14:42:15 +05:30
def main():
2014-10-16 20:06:45 +02:00
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)
2014-10-16 23:25:33 +02:00
# 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)
2014-10-16 20:06:45 +02:00
for profile_name in profiles_to_merge:
2014-10-16 23:25:33 +02:00
aaui.UI_Info("\n\n" + _("Merging profile for %s" % profile_name))
2014-10-16 20:06:45 +02:00
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)
2013-09-23 02:14:11 +05:30
#Get rid of common/superfluous stuff
2016-10-01 20:09:36 +02:00
mergeprofiles.clear_common()
2014-02-13 08:31:59 -08:00
2014-09-04 01:49:47 +02:00
# if not args.auto:
if 1 == 1: # workaround to avoid lots of whitespace changes
2014-07-29 12:39:12 +02:00
if merge_mode == 3:
2014-10-16 20:06:45 +02:00
mergeprofiles.ask_the_questions('other', merging_profile)
2014-02-13 08:31:59 -08:00
2014-07-29 12:39:12 +02:00
mergeprofiles.clear_common()
2013-09-23 23:56:28 +05:30
2014-10-16 20:06:45 +02:00
mergeprofiles.ask_the_questions('base', merging_profile)
2014-02-13 08:31:59 -08:00
2014-10-07 18:36:01 +05:30
q = aaui.PromptQuestion()
q.title = _('Changed Local Profiles')
q.explanation = _('The following local profiles were changed. Would you like to save them?')
2014-10-16 20:06:45 +02:00
q.functions = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT', 'CMD_IGNORE_ENTRY']
2014-10-07 18:36:01 +05:30
q.default = 'CMD_VIEW_CHANGES'
2014-10-16 23:35:06 +02:00
q.options = [merging_profile]
2014-10-07 18:36:01 +05:30
q.selected = 0
2013-09-23 19:32:25 +05:30
ans = ''
arg = None
programs = list(mergeprofiles.user.aa.keys())
program = programs[0]
while ans != 'CMD_SAVE_CHANGES':
2014-10-07 18:36:01 +05:30
ans, arg = q.promptUser()
2013-09-23 19:32:25 +05:30
if ans == 'CMD_SAVE_CHANGES':
apparmor.aa.write_profile_ui_feedback(program)
apparmor.aa.reload_base(program)
elif ans == 'CMD_VIEW_CHANGES':
for program in programs:
apparmor.aa.original_aa[program] = apparmor.aa.deepcopy(apparmor.aa.aa[program])
#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)
2014-10-16 20:06:45 +02:00
elif ans == 'CMD_IGNORE_ENTRY':
break
2014-02-13 08:31:59 -08:00
2013-09-22 22:51:30 +05:30
2013-09-12 14:42:15 +05:30
class Merge(object):
def __init__(self, profiles):
user, base, other = profiles
2013-09-22 22:51:30 +05:30
2013-09-12 14:42:15 +05:30
#Read and parse base profile and save profile data, include data from it and reset them
2013-09-23 19:32:25 +05:30
apparmor.aa.read_profile(base, True)
2013-09-23 03:47:15 +05:30
self.base = cleanprofile.Prof(base)
2013-09-23 02:14:11 +05:30
2014-10-16 20:06:45 +02:00
reset_aa()
2013-09-22 22:51:30 +05:30
2013-09-12 14:42:15 +05:30
#Read and parse other profile and save profile data, include data from it and reset them
2014-07-29 12:39:12 +02:00
if merge_mode == 3:
apparmor.aa.read_profile(other, True)
self.other = cleanprofile.Prof(other)
2014-10-16 20:06:45 +02:00
reset_aa()
2013-09-22 22:51:30 +05:30
2013-09-12 14:42:15 +05:30
#Read and parse user profile
2014-07-29 12:39:12 +02:00
apparmor.aa.read_profile(user, True)
2013-09-23 03:47:15 +05:30
self.user = cleanprofile.Prof(user)
2013-09-22 22:51:30 +05:30
2013-09-12 14:42:15 +05:30
def clear_common(self):
2013-09-23 02:14:11 +05:30
deleted = 0
2014-07-29 12:39:12 +02:00
if merge_mode == 3:
#Remove off the parts in other profile which are common/superfluous from user profile
user_other = cleanprofile.CleanProf(False, self.user, self.other)
deleted += user_other.compare_profiles()
2014-02-13 08:31:59 -08:00
2013-09-23 02:14:11 +05:30
#Remove off the parts in base profile which are common/superfluous from user profile
2013-09-23 03:47:15 +05:30
user_base = cleanprofile.CleanProf(False, self.user, self.base)
2013-09-23 02:14:11 +05:30
deleted += user_base.compare_profiles()
2014-02-13 08:31:59 -08:00
2014-07-29 12:39:12 +02:00
if merge_mode == 3:
#Remove off the parts in other profile which are common/superfluous from base profile
base_other = cleanprofile.CleanProf(False, self.base, self.other)
deleted += base_other.compare_profiles()
2013-09-23 02:14:11 +05:30
2016-10-01 20:12:30 +02:00
def ask_conflict_mode(self, profile, hat, old_profile, merge_profile):
'''ask user about conflicting exec rules'''
for oldrule in old_profile['file'].rules:
conflictingrules = merge_profile['file'].get_exec_conflict_rules(oldrule)
if conflictingrules.rules:
2014-10-07 18:36:01 +05:30
q = aaui.PromptQuestion()
2016-10-01 20:12:30 +02:00
q.headers = [_('Path'), oldrule.path.regex]
2014-10-07 18:36:01 +05:30
q.headers += [_('Select the appropriate mode'), '']
2013-09-23 23:05:25 +05:30
options = []
2016-10-01 20:12:30 +02:00
options.append(oldrule.get_clean())
for rule in conflictingrules.rules:
options.append(rule.get_clean())
2014-10-07 18:36:01 +05:30
q.options = options
q.functions = ['CMD_ALLOW', 'CMD_ABORT']
2013-09-23 23:05:25 +05:30
done = False
while not done:
2014-10-07 18:36:01 +05:30
ans, selected = q.promptUser()
2013-09-23 23:05:25 +05:30
if ans == 'CMD_ALLOW':
2013-09-23 23:56:28 +05:30
if selected == 0:
2016-10-01 20:12:30 +02:00
pass # just keep the existing rule
elif selected > 0:
# replace existing rule with merged one
old_profile['file'].delete(oldrule)
old_profile['file'].add(conflictingrules.rules[selected - 1])
2013-09-23 23:05:25 +05:30
else:
2015-05-18 01:35:51 +02:00
raise AppArmorException(_('Unknown selection'))
2016-10-01 20:12:30 +02:00
for rule in conflictingrules.rules:
merge_profile['file'].delete(rule) # make sure aa-mergeprof doesn't ask to add conflicting rules later
2013-09-23 23:05:25 +05:30
done = True
2014-02-13 08:31:59 -08:00
2014-10-16 20:06:45 +02:00
def ask_the_questions(self, other, profile):
2015-06-08 22:25:44 +02:00
aa = self.user.aa # keep references so that the code in this function can use the short name
changed = apparmor.aa.changed # (and be more in sync with aa.py ask_the_questions())
2013-09-23 19:32:25 +05:30
if other == 'other':
other = self.other
else:
other = self.base
#print(other.aa)
2014-02-13 08:31:59 -08:00
2013-09-23 19:32:25 +05:30
#Add the file-wide includes from the other profile to the user profile
2016-10-01 20:20:27 +02:00
apparmor.aa.loadincludes()
2013-09-23 19:32:25 +05:30
done = False
2014-10-16 20:22:52 +02:00
options = []
for inc in other.filelist[other.filename]['include'].keys():
if not inc in self.user.filelist[self.user.filename]['include'].keys():
options.append('#include <%s>' %inc)
2013-09-23 19:32:25 +05:30
default_option = 1
2014-10-07 18:36:01 +05:30
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'
2013-09-23 19:32:25 +05:30
while not done and options:
2014-10-16 23:25:33 +02:00
ans, selected = q.promptUser()
2013-09-23 19:32:25 +05:30
if ans == 'CMD_IGNORE_ENTRY':
done = True
elif ans == 'CMD_ALLOW':
selection = options[selected]
2015-06-19 21:41:41 +02:00
inc = re_match_include(selection)
2013-09-23 19:32:25 +05:30
self.user.filelist[self.user.filename]['include'][inc] = True
options.pop(selected)
2014-07-28 00:24:26 +02:00
aaui.UI_Info(_('Adding %s to the file.') % selection)
2014-10-16 23:25:33 +02:00
elif ans == 'CMD_FINISHED':
return
2014-02-13 08:31:59 -08:00
2013-09-23 19:32:25 +05:30
sev_db = apparmor.aa.sev_db
if not sev_db:
sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
2014-10-07 18:36:01 +05:30
2016-05-10 14:32:46 +02:00
sev_db.unload_variables()
sev_db.load_variables(get_profile_filename(profile))
2014-10-16 20:06:45 +02:00
for hat in sorted(other.aa[profile].keys()):
[41/38] let aa-mergeprof ask about new hats and subprofiles
If a merged profile contains additional hats or subprofiles, the "old"
aa-mergeprof silently created them as additional hasher elements (partly
buggy, because subprofiles would end up as '^/subprofile' instead of
'profile /subprofile'). After switching to FileRule, aa-mergeprof crashes
on new hats or subprofiles.
This patch adds code to ask the user if the new hat or subprofile should
be added - which means this patch replaces two bugs (crash + silently
adding subprofiles and hats) with a new feature ;-)
The new questions also add a new text CMD_ADDSUBPROFILE in ui.py.
Finally, the new "button" combinations get added to test-translations.py.
If you want to test, try to aa-mergeprof this profile (the subprofile
and hat are dummies, nothing ping would really require):
#include <tunables/global>
/{usr/,}bin/ping {
#include <abstractions/base>
#include <abstractions/consoles>
#include <abstractions/nameservice>
capability net_raw,
capability setuid,
network inet raw,
network inet6 raw,
/{,usr/}bin/ping mixr,
/etc/modules.conf r,
^hat {
/bin/hat r,
/bin/bash px,
}
profile /subprofile {
/bin/subprofile r,
/bin/bash px,
}
# Site-specific additions and overrides. See local/README for details.
#include <local/bin.ping>
}
Note that this patch is not covered by unittests, but it passed all my
manual tests.
Acked-by: Steve Beattie <steve@nxnw.org>
Bug: https://launchpad.net/bugs/1507469
2016-10-01 20:21:06 +02:00
if not aa[profile].get(hat):
ans = ''
while ans not in ['CMD_ADDHAT', 'CMD_ADDSUBPROFILE', 'CMD_DENY']:
q = aaui.PromptQuestion()
q.headers += [_('Profile'), profile]
if other.aa[profile][hat]['profile']:
q.headers += [_('Requested Subprofile'), hat]
q.functions.append('CMD_ADDSUBPROFILE')
else:
q.headers += [_('Requested Hat'), hat]
q.functions.append('CMD_ADDHAT')
q.functions += ['CMD_DENY', 'CMD_ABORT', 'CMD_FINISHED']
q.default = 'CMD_DENY'
ans = q.promptUser()[0]
if ans == 'CMD_FINISHED':
return
if ans == 'CMD_DENY':
continue # don't ask about individual rules if the user doesn't want the additional subprofile/hat
if other.aa[profile][hat]['profile']:
aa[profile][hat] = profile_storage(profile, hat, 'mergeprof ask_the_questions() - missing subprofile')
aa[profile][hat]['profile'] = True
else:
aa[profile][hat] = profile_storage(profile, hat, 'mergeprof ask_the_questions() - missing hat')
aa[profile][hat]['profile'] = False
2014-10-16 20:06:45 +02:00
#Add the includes from the other profile to the user profile
done = False
2014-10-16 20:22:52 +02:00
options = []
for inc in other.aa[profile][hat]['include'].keys():
2015-06-08 22:25:44 +02:00
if not inc in aa[profile][hat]['include'].keys():
2014-10-16 20:22:52 +02:00
options.append('#include <%s>' %inc)
2014-10-16 20:06:45 +02:00
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]
2015-06-19 21:41:41 +02:00
inc = re_match_include(selection)
2015-06-08 22:25:44 +02:00
deleted = apparmor.aa.delete_duplicates(aa[profile][hat], inc)
aa[profile][hat]['include'][inc] = True
2014-10-16 20:06:45 +02:00
options.pop(selected)
aaui.UI_Info(_('Adding %s to the file.') % selection)
if deleted:
aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
2014-10-16 23:25:33 +02:00
elif ans == 'CMD_FINISHED':
return
2014-10-16 20:06:45 +02:00
2016-10-01 20:12:30 +02:00
# check for and ask about conflicting exec modes
self.ask_conflict_mode(profile, hat, aa[profile][hat], other.aa[profile][hat])
2015-12-04 12:01:32 +01:00
for ruletype in apparmor.aa.ruletypes:
2015-05-29 23:03:51 +02:00
if other.aa[profile][hat].get(ruletype, False): # needed until we have proper profile initialization
for rule_obj in other.aa[profile][hat][ruletype].rules:
2015-05-29 01:12:38 +02:00
2015-06-08 22:25:44 +02:00
if is_known_rule(aa[profile][hat], ruletype, rule_obj):
2015-05-29 01:12:38 +02:00
continue
2014-10-16 20:06:45 +02:00
default_option = 1
options = []
2015-06-08 22:25:44 +02:00
newincludes = match_includes(aa[profile][hat], ruletype, rule_obj)
2014-10-16 20:06:45 +02:00
q = aaui.PromptQuestion()
if newincludes:
2015-06-06 14:02:02 +02:00
options += list(map(lambda inc: '#include <%s>' % inc, sorted(set(newincludes))))
2016-10-01 20:04:42 +02:00
if ruletype == 'file' and rule_obj.path:
options += propose_file_rules(aa[profile][hat], rule_obj)
else:
options.append(rule_obj.get_clean())
2014-02-13 08:31:59 -08:00
2014-10-16 20:06:45 +02:00
done = False
while not done:
2016-10-01 19:58:40 +02:00
q.options = options
q.selected = default_option - 1
2015-06-06 14:17:25 +02:00
q.headers = [_('Profile'), combine_name(profile, hat)]
2015-06-06 14:09:38 +02:00
q.headers += rule_obj.logprof_header()
2015-06-06 14:17:25 +02:00
# Load variables into sev_db? Not needed/used for capabilities and network rules.
2015-06-06 14:09:38 +02:00
severity = rule_obj.severity(sev_db)
if severity != sev_db.NOT_IMPLEMENTED:
q.headers += [_('Severity'), severity]
q.functions = available_buttons(rule_obj)
q.default = q.functions[0]
2014-10-16 20:06:45 +02:00
ans, selected = q.promptUser()
2016-10-01 19:58:40 +02:00
selection = options[selected]
2014-10-16 20:06:45 +02:00
if ans == 'CMD_IGNORE_ENTRY':
done = True
break
2014-02-13 08:31:59 -08:00
2014-10-16 23:25:33 +02:00
elif ans == 'CMD_FINISHED':
return
2015-06-06 14:02:02 +02:00
elif ans.startswith('CMD_AUDIT'):
2015-05-29 01:12:38 +02:00
if ans == 'CMD_AUDIT_NEW':
2015-05-29 23:03:51 +02:00
rule_obj.audit = True
rule_obj.raw_rule = None
2014-10-16 20:06:45 +02:00
else:
2015-05-29 23:03:51 +02:00
rule_obj.audit = False
rule_obj.raw_rule = None
2015-05-29 01:12:38 +02:00
2016-10-01 20:05:27 +02:00
options = set_options_audit_mode(rule_obj, options)
2015-05-29 01:12:38 +02:00
2014-10-16 20:06:45 +02:00
elif ans == 'CMD_ALLOW':
done = True
2015-06-08 22:25:44 +02:00
changed[profile] = True
2015-06-06 14:02:02 +02:00
2015-06-06 14:17:25 +02:00
inc = re_match_include(selection)
2015-06-06 14:02:02 +02:00
if inc:
2015-06-08 22:25:44 +02:00
deleted = delete_duplicates(aa[profile][hat], inc)
2014-02-13 08:31:59 -08:00
2015-06-08 22:25:44 +02:00
aa[profile][hat]['include'][inc] = True
2014-02-13 08:31:59 -08:00
2015-06-06 14:02:02 +02:00
aaui.UI_Info(_('Adding %s to profile.') % selection)
2014-10-16 20:06:45 +02:00
if deleted:
aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
2014-02-13 08:31:59 -08:00
2013-09-23 19:32:25 +05:30
else:
2016-10-01 19:58:40 +02:00
rule_obj = selection_to_rule_obj(rule_obj, selection)
2016-10-01 20:13:49 +02:00
deleted = aa[profile][hat][ruletype].add(rule_obj, cleanup=True)
2014-10-16 20:06:45 +02:00
2015-06-06 14:02:02 +02:00
aaui.UI_Info(_('Adding %s to profile.') % rule_obj.get_clean())
2016-10-01 20:13:49 +02:00
if deleted:
aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
2014-10-16 20:06:45 +02:00
elif ans == 'CMD_DENY':
2016-10-01 19:58:40 +02:00
if re_match_include(selection):
aaui.UI_Important("Denying via an include file isn't supported by the AppArmor tools")
else:
done = True
changed[profile] = True
rule_obj = selection_to_rule_obj(rule_obj, selection)
rule_obj.deny = True
rule_obj.raw_rule = None # reset raw rule after manually modifying rule_obj
2016-10-01 20:13:49 +02:00
deleted = aa[profile][hat][ruletype].add(rule_obj, cleanup=True)
2016-10-01 19:58:40 +02:00
aaui.UI_Info(_('Adding %s to profile.') % rule_obj.get_clean())
2016-10-01 20:13:49 +02:00
if deleted:
aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
2015-06-06 14:02:02 +02:00
2016-10-01 19:58:40 +02:00
elif ans == 'CMD_GLOB':
if not re_match_include(selection):
globbed_rule_obj = selection_to_rule_obj(rule_obj, selection)
globbed_rule_obj.glob()
options, default_option = add_to_options(options, globbed_rule_obj.get_raw())
elif ans == 'CMD_GLOBEXT':
if not re_match_include(selection):
globbed_rule_obj = selection_to_rule_obj(rule_obj, selection)
globbed_rule_obj.glob_ext()
options, default_option = add_to_options(options, globbed_rule_obj.get_raw())
2014-10-16 20:06:45 +02:00
2016-10-01 20:01:53 +02:00
elif ans == 'CMD_NEW':
if not re_match_include(selection):
edit_rule_obj = selection_to_rule_obj(rule_obj, selection)
prompt, oldpath = edit_rule_obj.edit_header()
newpath = aaui.UI_GetString(prompt, oldpath)
if newpath:
try:
input_matches_path = rule_obj.validate_edit(newpath) # note that we check against the original rule_obj here, not edit_rule_obj (which might be based on a globbed path)
except AppArmorException:
aaui.UI_Important(_('The path you entered is invalid (not starting with / or a variable)!'))
continue
if not input_matches_path:
ynprompt = _('The specified path does not match this log entry:\n\n Log Entry: %(path)s\n Entered Path: %(ans)s\nDo you really want to use this path?') % { 'path': oldpath, 'ans': newpath }
key = aaui.UI_YesNo(ynprompt, 'n')
if key == 'n':
continue
edit_rule_obj.store_edit(newpath)
options, default_option = add_to_options(options, edit_rule_obj.get_raw())
2016-10-01 20:04:42 +02:00
apparmor.aa.user_globs[newpath] = AARE(newpath, True)
2016-10-01 20:01:53 +02:00
2014-10-16 20:06:45 +02:00
else:
done = False
2013-09-12 14:42:15 +05:30
2013-09-23 02:14:11 +05:30
if __name__ == '__main__':
main()