File: aa-mergeprof

package info (click to toggle)
apparmor 4.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 34,800 kB
  • sloc: ansic: 24,940; python: 24,595; sh: 12,524; cpp: 9,024; yacc: 2,061; makefile: 1,921; lex: 1,215; pascal: 1,145; perl: 1,033; ruby: 365; lisp: 282; exp: 250; java: 212; xml: 159
file content (136 lines) | stat: -rwxr-xr-x 4,881 bytes parent folder | download
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()