diff --git a/utils/aa-mergeprof b/utils/aa-mergeprof index 230148b0f..c26bd9a07 100755 --- a/utils/aa-mergeprof +++ b/utils/aa-mergeprof @@ -34,18 +34,19 @@ args = parser.parse_args() profiles = [args.mine, args.base, args.other] + def main(): mergeprofiles = Merge(profiles) #Get rid of common/superfluous stuff mergeprofiles.clear_common() - + if not args.auto: mergeprofiles.ask_the_questions('other') - + mergeprofiles.clear_common() mergeprofiles.ask_the_questions('base') - + q = apparmor.aa.hasher() q['title'] = 'Changed Local Profiles' q['headers'] = [] @@ -69,7 +70,7 @@ 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) - + class Merge(object): def __init__(self, profiles): @@ -103,11 +104,11 @@ class Merge(object): #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() - + #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() - + #Remove off the parts in other profile which are common/superfluous from base profile # base_other = cleanprofile.CleanProf(False, self.base, self.other) # XXX base_other not used? deleted += user_base.compare_profiles() @@ -147,14 +148,14 @@ class Merge(object): else: raise apparmor.aa.AppArmorException(_('Unknown selection')) done = True - + def ask_the_questions(self, other): if other == 'other': other = self.other else: other = self.base #print(other.aa) - + #Add the file-wide includes from the other profile to the user profile done = False options = list(map(lambda inc: '#include <%s>' %inc, sorted(other.filelist[other.filename]['include'].keys()))) @@ -175,8 +176,7 @@ class Merge(object): self.user.filelist[self.user.filename]['include'][inc] = True options.pop(selected) apparmor.aa.UI_Info(_('Adding %s to the file.') % selection) - - + sev_db = apparmor.aa.sev_db if not sev_db: sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown')) @@ -205,7 +205,7 @@ class Merge(object): apparmor.aa.UI_Info(_('Adding %s to the file.') % selection) if deleted: apparmor.aa.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): @@ -218,22 +218,22 @@ class Merge(object): q = apparmor.aa.hasher() 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 = apparmor.aa.UI_PromptUser(q) @@ -241,7 +241,7 @@ class Merge(object): if ans == 'CMD_IGNORE_ENTRY': done = True break - + if ans == 'CMD_ALLOW': selection = '' if options: @@ -252,28 +252,28 @@ class Merge(object): inc = match deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc) self.user.aa[profile][hat]['include'][inc] = True - + apparmor.aa.UI_Info(_('Adding %s to profile.') % selection) if deleted: apparmor.aa.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 - + apparmor.aa.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 - + apparmor.aa.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()): @@ -290,37 +290,37 @@ class Merge(object): 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.aa.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 @@ -329,32 +329,32 @@ class Merge(object): mode = mode - apparmor.aamode.ALL_AA_EXEC_TYPE if not allow_mode & apparmor.aa.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 @@ -362,14 +362,14 @@ class Merge(object): 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 @@ -389,19 +389,19 @@ class Merge(object): 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']: @@ -411,7 +411,7 @@ class Merge(object): q = apparmor.aa.hasher() q['headers'] = [_('Profile'), apparmor.aa.combine_name(profile, hat), _('Path'), path] - + if allow_mode: mode |= allow_mode tail = '' @@ -428,7 +428,7 @@ class Merge(object): 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: @@ -438,10 +438,10 @@ class Merge(object): 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 = '' @@ -456,26 +456,26 @@ class Merge(object): 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 = apparmor.aa.UI_PromptUser(q) - + if ans == 'CMD_IGNORE_ENTRY': done = True break - + if ans == 'CMD_OTHER': audit_toggle, owner_toggle = apparmor.aa.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode) elif ans == 'CMD_USER_TOGGLE': @@ -497,7 +497,7 @@ class Merge(object): apparmor.aa.UI_Info(_('Adding %s to profile.') % path) if deleted: apparmor.aa.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'] @@ -505,14 +505,14 @@ class Merge(object): 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: @@ -521,36 +521,36 @@ class Merge(object): 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 - + apparmor.aa.UI_Info(_('Adding %s %s to profile') % (path, apparmor.aa.mode_to_str_user(mode))) if deleted: apparmor.aa.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): @@ -564,29 +564,29 @@ class Merge(object): 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 @@ -608,24 +608,24 @@ class Merge(object): 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 = apparmor.aa.UI_PromptUser(q) if ans == 'CMD_IGNORE_ENTRY': done = True break - + if ans.startswith('CMD_AUDIT'): audit_toggle = not audit_toggle audit = '' @@ -639,7 +639,7 @@ class Merge(object): 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] @@ -648,34 +648,31 @@ class Merge(object): 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 - + apparmor.aa.UI_Info(_('Adding %s to profile') % selection) if deleted: apparmor.aa.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 - + apparmor.aa.UI_Info(_('Adding network access %s %s to profile.') % (family, 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 apparmor.aa.UI_Info(_('Denying network access %s %s to profile') % (family, sock_type)) - + else: done = False - - - if __name__ == '__main__': main()