Skip to content
Snippets Groups Projects

ospack: Switch AppArmor profiles to complain mode

3 unresolved threads
5 files
+ 124
0
Compare changes
  • Side-by-side
  • Inline
Files
5
+ 70
0
#!/usr/bin/env python3
    • So why hacking up all the profile files rather then making symlinks to the various profiles from /etc/apparmor.d/force-complain/ which seems more robust and easier to use?

      • Author Owner

        Because I looked at what aa-complain does and I didn't stumble on anyone documenting the force-complain symlinks, so now I'm mad at AppArmor. Well, not really, luckily this is less than a hour of trivial copying and pasting, so I'm more than happy to rework this one to use the symlinks. I really wonder why aa-complain took the long-winded approach though...

      • changed this line in version 2 of the diff

      • Please register or sign in to reply
Please register or sign in to reply
import codecs
import os.path
import re
import shutil
import sys
import tempfile
RE_PATH = '/\S*|"/[^"]*"' # filename (starting with '/') without spaces, or quoted filename.
RE_PROFILE_PATH_OR_VAR = '(?P<%s>(' + RE_PATH + '|@{\S+}\S*|"@{\S+}[^"]*"))' # quoted or unquoted filename or variable. %s is the match group name
RE_PROFILE_NAME = '(?P<%s>(\S+|"[^"]+"))' # string without spaces, or quoted string. %s is the match group name
RE_XATTRS = '(\s+xattrs\s*=\s*\((?P<xattrs>([^)=]+=[^)=]+\s?)+)\)\s*)?'
RE_FLAGS = '(\s+(flags\s*=\s*)?\((?P<flags>[^)]+)\))?'
RE_EOL = '\s*(?P<comment>#.*?)?\s*$' # optional whitespace, optional <comment>, optional whitespace, end of the line
RE_PROFILE_START = re.compile(
'^(?P<leadingspace>\s*)' +
'(' +
RE_PROFILE_PATH_OR_VAR % 'plainprofile' + # just a path
'|' + # or
'(' + 'profile' + '\s+' + RE_PROFILE_NAME % 'namedprofile' + '(\s+' + RE_PROFILE_PATH_OR_VAR % 'attachment' + ')?' + ')' + # 'profile', profile name, optionally attachment
')' +
RE_XATTRS +
RE_FLAGS +
'\s*\{' +
RE_EOL)
def open_file_read(path, encoding='UTF-8'):
'''Open specified file read-only'''
return open_file_anymode('r', path, encoding)
def open_file_write(path):
'''Open specified file in write/overwrite mode'''
return open_file_anymode('w', path, 'UTF-8')
def open_file_anymode(mode, path, encoding='UTF-8'):
'''Open specified file in specified mode'''
errorhandling = 'surrogateescape'
if sys.version_info[0] < 3:
errorhandling = 'replace'
orig = codecs.open(path, mode, encoding, errors=errorhandling)
return orig
def set_complain(prof_filename):
"""Reads the old profile file and updates the flags accordingly"""
profile_dir = os.path.dirname(prof_filename) or '.'
with open_file_read(prof_filename) as f_in:
temp_file = tempfile.NamedTemporaryFile('w', prefix=prof_filename, suffix='~', delete=False, dir=profile_dir)
shutil.copymode(prof_filename, temp_file.name)
with open_file_write(temp_file.name) as f_out:
for line in f_in:
matches = RE_PROFILE_START.search(line)
if matches:
if matches.group('flags') is None:
if matches.group('plainprofile'):
start, end = matches.span('plainprofile')
else:
start, end = matches.span('attachment')
line = line[:end] + ' flags=(complain)' + line[end:]
elif 'complain' not in matches.group('flags'):
start, end = matches.span('flags')
line = line[:end] + ',complain' + line[end:]
f_out.write(line)
os.rename(temp_file.name, prof_filename)
for prof_filename in sys.argv[1:]:
set_complain(prof_filename)
Loading