apparmor/utils/aa-mergeprof
Christian Boltz 0cf15d54b6
aa-mergeprof: drop separate code asking for include rules
... because this is now done via IncludeRule, and keeping the separate
code would mean asking twice.

Note that the user interface changes slightly.

The old workflow was

    1 - #include <foo>
    2 - #include <bar>
    3 - #include <baz>
    [select 2 and (A)dd, then get the next question for the remainder]

    1 - #include <foo>
    2 - #include <baz>
    [(A)dd another one, or (I)gnore the remainder]

The new workflow will ask separately for each abstraction, and you can
(A)dd or (I)gnore it. This is probably easier to understand because it's
basically a yes/no question.
2020-05-20 18:52:16 +02:00

147 lines
5 KiB
Python
Executable file

#! /usr/bin/python3
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2014-2018 Christian Boltz <apparmor@cboltz.de>
#
# 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.
#
# ----------------------------------------------------------------------
import argparse
import os
import apparmor.aa
import apparmor.severity
import apparmor.cleanprofile as cleanprofile
import apparmor.ui as aaui
from apparmor.common import AppArmorException
# setup exception handling
from apparmor.fail import enable_aa_exception_handler
enable_aa_exception_handler()
# setup module translations
from apparmor.translations import init_translation
_ = init_translation()
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=_('Profile(s) to merge'))
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
apparmor.aa.init_aa()
profiles = args.files
profiledir = args.dir
if profiledir:
apparmor.aa.profile_dir = apparmor.aa.get_full_path(profiledir)
if not os.path.isdir(apparmor.aa.profile_dir):
raise 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.active_profiles = apparmor.aa.ProfileList()
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.active_profiles.profiles_in_file(file_name):
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_from_profile_name(profile_name, True)
reset_aa()
return profile_to_filename
def main():
base_profile_to_file = find_profiles_from_files(profiles)
profiles_to_merge = set(base_profile_to_file.keys())
user_profile_to_file = find_files_from_profiles(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)
act(user_file, base_file, profile_name)
reset_aa()
def act(user_file, base_file, merging_profile):
mergeprofiles = Merge(user_file, base_file)
#Get rid of common/superfluous stuff
mergeprofiles.clear_common()
mergeprofiles.ask_merge_questions()
apparmor.aa.changed[merging_profile] = True # force asking to save the profile
apparmor.aa.save_profiles(True)
class Merge(object):
def __init__(self, user, base):
#Read and parse base profile and save profile data, include data from it and reset them
apparmor.aa.read_profile(base, True)
self.base = cleanprofile.Prof(base)
reset_aa()
#Read and parse user profile
apparmor.aa.read_profile(user, True)
self.user = cleanprofile.Prof(user)
def clear_common(self):
deleted = 0
#Remove off the parts in base profile which are common/superfluous from user profile
user_base = cleanprofile.CleanProf(False, self.user, self.base)
deleted += user_base.compare_profiles()
def ask_merge_questions(self):
other = self.base
log_dict = {'merge': other.aa}
apparmor.aa.loadincludes()
if not apparmor.aa.sev_db:
apparmor.aa.sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
# ask about preamble rules
apparmor.aa.ask_rule_questions(
other.active_profiles.files[other.filename], # prof_events aka log_dict
'[preamble]', # displayed profile name
self.user.active_profiles.files[self.user.filename], # profile to update
['abi', 'inc_ie'] # rule types - TODO: don't hardcode
)
apparmor.aa.ask_the_questions(log_dict)
if __name__ == '__main__':
main()