1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
#! /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 apparmor.aa
import apparmor.cleanprofile as cleanprofile
import apparmor.severity
import apparmor.ui as aaui
from apparmor.fail import enable_aa_exception_handler
from apparmor.translations import init_translation
enable_aa_exception_handler() # setup exception handling
_ = init_translation() # setup module translations
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'))
parser.add_argument('--configdir', type=str, help=argparse.SUPPRESS)
args = parser.parse_args()
args.other = None
apparmor.aa.init_aa(confdir=args.configdir, profiledir=args.dir)
profiles = args.files
def find_profiles_from_files(files):
profile_to_filename = dict()
for file_name in files:
try:
apparmor.aa.read_profile(file_name, True, read_error_fatal=True)
for profile_name in apparmor.aa.active_profiles.profiles_in_file(file_name):
profile_to_filename[profile_name] = file_name
except IOError:
pass
apparmor.aa.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)
apparmor.aa.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)
apparmor.aa.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)
apparmor.aa.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': apparmor.aa.split_to_merged(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()
|