2013-09-28 20:43:06 +05:30
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
2014-08-17 18:16:33 +02:00
# Copyright (C) 2014 Christian Boltz <apparmor@cboltz.de>
2013-09-28 20:43:06 +05:30
#
# 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.
#
# ----------------------------------------------------------------------
2013-07-23 04:35:51 +05:30
# No old version logs, only 2.6 + supported
2015-04-02 23:40:15 +02:00
from __future__ import division , with_statement
2013-07-06 18:57:06 +05:30
import inspect
2013-07-04 04:12:04 +05:30
import os
import re
2013-07-17 20:38:13 +05:30
import shutil
2013-07-06 18:57:06 +05:30
import subprocess
2013-07-04 04:12:04 +05:30
import sys
2013-07-24 22:12:34 +05:30
import time
2013-07-06 18:57:06 +05:30
import traceback
2013-07-09 03:46:26 +05:30
import atexit
2013-07-17 20:38:13 +05:30
import tempfile
2013-07-09 03:46:26 +05:30
import apparmor . config
2013-08-11 15:22:07 +05:30
import apparmor . logparser
2013-07-09 03:46:26 +05:30
import apparmor . severity
2013-08-31 04:13:05 +05:30
from copy import deepcopy
2014-02-13 10:01:03 -08:00
from apparmor . common import ( AppArmorException , open_file_read , valid_path , hasher ,
2014-02-11 16:23:21 -08:00
open_file_write , convert_regexp , DebugLogger )
2013-07-06 18:57:06 +05:30
2014-02-10 22:17:21 -08:00
import apparmor . ui as aaui
2013-08-26 00:23:59 +05:30
2014-02-10 22:17:21 -08:00
from apparmor . aamode import ( str_to_mode , mode_to_str , contains , split_mode ,
mode_to_str_user , mode_contains , AA_OTHER ,
flatten_mode , owner_flatten_mode )
2014-11-13 19:17:10 +01:00
from apparmor . regex import ( RE_PROFILE_START , RE_PROFILE_END , RE_PROFILE_CAP , RE_PROFILE_LINK ,
RE_PROFILE_CHANGE_PROFILE , RE_PROFILE_ALIAS , RE_PROFILE_RLIMIT ,
RE_PROFILE_BOOLEAN , RE_PROFILE_VARIABLE , RE_PROFILE_CONDITIONAL ,
RE_PROFILE_CONDITIONAL_VARIABLE , RE_PROFILE_CONDITIONAL_BOOLEAN ,
RE_PROFILE_BARE_FILE_ENTRY , RE_PROFILE_PATH_ENTRY , RE_PROFILE_NETWORK ,
RE_NETWORK_FAMILY_TYPE , RE_NETWORK_FAMILY , RE_PROFILE_CHANGE_HAT ,
RE_PROFILE_HAT_DEF , RE_PROFILE_DBUS , RE_PROFILE_MOUNT ,
RE_PROFILE_SIGNAL , RE_PROFILE_PTRACE , RE_PROFILE_PIVOT_ROOT ,
2015-03-03 20:18:30 +01:00
RE_PROFILE_UNIX , RE_RULE_HAS_COMMA , RE_HAS_COMMENT_SPLIT ,
2015-04-13 18:24:20 -07:00
strip_quotes , parse_profile_start_line )
2014-11-13 19:17:10 +01:00
2014-03-07 09:58:54 -08:00
import apparmor . rules as aarules
2014-02-10 22:17:21 -08:00
from apparmor . yasti import SendDataToYast , GetDataFromYast , shutdown_yast
2013-07-17 20:38:13 +05:30
2014-02-10 22:15:05 -08:00
# setup module translations
2014-02-11 16:23:21 -08:00
from apparmor . translations import init_translation
_ = init_translation ( )
2014-02-10 22:15:05 -08:00
2013-07-06 18:57:06 +05:30
# Setup logging incase of debugging is enabled
2013-08-09 11:04:32 +05:30
debug_logger = DebugLogger ( ' aa ' )
2013-07-04 04:12:04 +05:30
CONFDIR = ' /etc/apparmor '
running_under_genprof = False
unimplemented_warning = False
2013-07-18 05:29:54 +05:30
2013-09-22 22:51:30 +05:30
# The database for severity
2013-07-04 04:12:04 +05:30
sev_db = None
# The file to read log messages from
### Was our
filename = None
cfg = None
repo_cfg = None
parser = None
ldd = None
logger = None
profile_dir = None
extra_profile_dir = None
### end our
# To keep track of previously included profile fragments
include = dict ( )
existing_profiles = dict ( )
2014-02-10 22:20:36 -08:00
seen_events = 0 # was our
2013-07-04 04:12:04 +05:30
# To store the globs entered by users so they can be provided again
user_globs = [ ]
2014-03-20 14:27:24 -05:00
# The key for representing bare rules such as "capability," or "file,"
2014-04-03 21:58:59 -05:00
ALL = ' \0 ALL '
2014-03-20 14:27:24 -05:00
2013-07-04 04:12:04 +05:30
## Variables used under logprof
### Were our
2014-02-01 06:14:05 +05:30
t = hasher ( ) # dict()
2013-08-11 15:22:07 +05:30
transitions = hasher ( )
2013-07-28 08:23:46 +05:30
aa = hasher ( ) # Profiles originally in sd, replace by aa
2014-02-10 22:20:36 -08:00
original_aa = hasher ( )
2013-07-28 08:23:46 +05:30
extras = hasher ( ) # Inactive profiles from extras
2013-07-04 04:12:04 +05:30
### end our
log = [ ]
2013-08-10 12:46:22 +05:30
pid = dict ( )
2013-07-04 04:12:04 +05:30
2014-02-01 06:14:05 +05:30
seen = hasher ( ) # dir()
2013-08-11 15:22:07 +05:30
profile_changes = hasher ( )
2013-07-28 08:23:46 +05:30
prelog = hasher ( )
2014-02-10 22:20:36 -08:00
log_dict = hasher ( ) # dict()
2013-07-04 04:12:04 +05:30
changed = dict ( )
created = [ ]
2013-07-28 08:23:46 +05:30
skip = hasher ( )
2014-02-10 22:20:36 -08:00
helpers = dict ( ) # Preserve this between passes # was our
2013-07-04 04:12:04 +05:30
### logprof ends
2013-07-28 08:23:46 +05:30
filelist = hasher ( ) # File level variables and stuff in config files
2013-07-04 04:12:04 +05:30
2013-07-06 18:57:06 +05:30
def on_exit ( ) :
""" Shutdowns the logger and records exit if debugging enabled """
2013-08-09 11:04:32 +05:30
debug_logger . debug ( ' Exiting.. ' )
debug_logger . shutdown ( )
2013-09-22 22:51:30 +05:30
2013-07-06 18:57:06 +05:30
# Register the on_exit method with atexit
atexit . register ( on_exit )
def check_for_LD_XXX ( file ) :
2013-09-22 22:51:30 +05:30
""" Returns True if specified program contains references to LD_PRELOAD or
2013-07-18 05:29:54 +05:30
LD_LIBRARY_PATH to give the Px / Ux code better suggestions """
2013-07-06 18:57:06 +05:30
if not os . path . isfile ( file ) :
return False
size = os . stat ( file ) . st_size
2013-07-23 04:35:51 +05:30
# Limit to checking files under 100k for the sake of speed
2014-02-10 22:20:36 -08:00
if size > 100000 :
2013-07-06 18:57:06 +05:30
return False
2014-08-17 18:16:33 +02:00
with open ( file , ' rb ' ) as f_in :
2013-07-06 18:57:06 +05:30
for line in f_in :
2014-08-17 18:16:33 +02:00
if b ' LD_PRELOAD ' in line or b ' LD_LIBRARY_PATH ' in line :
return True
return False
2013-07-06 18:57:06 +05:30
def fatal_error ( message ) :
2013-08-09 11:04:32 +05:30
# Get the traceback to the message
tb_stack = traceback . format_list ( traceback . extract_stack ( ) )
tb_stack = ' ' . join ( tb_stack )
# Append the traceback to message
message = message + ' \n ' + tb_stack
debug_logger . error ( message )
2013-07-06 18:57:06 +05:30
caller = inspect . stack ( ) [ 1 ] [ 3 ]
2013-09-22 22:51:30 +05:30
2013-07-06 18:57:06 +05:30
# If caller is SendDataToYast or GetDatFromYast simply exit
2014-02-10 22:20:36 -08:00
if caller == ' SendDataToYast ' or caller == ' GetDatFromYast ' :
2013-07-18 05:29:54 +05:30
sys . exit ( 1 )
2013-09-22 22:51:30 +05:30
2013-07-06 18:57:06 +05:30
# Else tell user what happened
2014-02-10 22:17:21 -08:00
aaui . UI_Important ( message )
2013-07-06 18:57:06 +05:30
shutdown_yast ( )
sys . exit ( 1 )
2013-09-22 22:51:30 +05:30
2014-11-27 23:20:26 +01:00
def check_for_apparmor ( filesystem = ' /proc/filesystems ' , mounts = ' /proc/mounts ' ) :
2014-11-27 18:34:45 +01:00
""" Finds and returns the mountpoint for apparmor None otherwise """
2013-07-04 04:12:04 +05:30
support_securityfs = False
aa_mountpoint = None
if valid_path ( filesystem ) :
with open_file_read ( filesystem ) as f_in :
for line in f_in :
if ' securityfs ' in line :
support_securityfs = True
2014-11-27 18:34:45 +01:00
break
if valid_path ( mounts ) and support_securityfs :
2013-07-04 04:12:04 +05:30
with open_file_read ( mounts ) as f_in :
for line in f_in :
2014-11-27 18:34:45 +01:00
split = line . split ( )
if len ( split ) > 2 and split [ 2 ] == ' securityfs ' :
mountpoint = split [ 1 ] + ' /apparmor '
# Check if apparmor is actually mounted there
2014-11-27 23:20:26 +01:00
# XXX valid_path() only checks the syntax, but not if the directory exists!
2014-11-27 18:34:45 +01:00
if valid_path ( mountpoint ) and valid_path ( mountpoint + ' /profiles ' ) :
aa_mountpoint = mountpoint
break
2013-07-04 04:12:04 +05:30
return aa_mountpoint
def which ( file ) :
2013-07-06 18:57:06 +05:30
""" Returns the executable fullpath for the file, None otherwise """
2014-02-10 22:20:36 -08:00
if sys . version_info > = ( 3 , 3 ) :
2013-09-12 14:42:15 +05:30
return shutil . which ( file )
env_dirs = os . getenv ( ' PATH ' ) . split ( ' : ' )
for env_dir in env_dirs :
env_path = env_dir + ' / ' + file
# Test if the path is executable or not
if os . access ( env_path , os . X_OK ) :
return env_path
return None
2013-09-22 22:51:30 +05:30
2013-07-06 18:57:06 +05:30
def get_full_path ( original_path ) :
""" Return the full path after resolving any symlinks """
path = original_path
link_count = 0
2013-07-09 03:46:26 +05:30
if not path . startswith ( ' / ' ) :
2013-07-06 18:57:06 +05:30
path = os . getcwd ( ) + ' / ' + path
while os . path . islink ( path ) :
link_count + = 1
if link_count > 64 :
2013-09-21 01:08:34 +05:30
fatal_error ( _ ( " Followed too many links while resolving %s " ) % ( original_path ) )
2013-07-06 18:57:06 +05:30
direc , file = os . path . split ( path )
link = os . readlink ( path )
# If the link an absolute path
if link . startswith ( ' / ' ) :
path = link
else :
# Link is relative path
path = direc + ' / ' + link
return os . path . realpath ( path )
def find_executable ( bin_path ) :
2013-08-13 00:43:20 +05:30
""" Returns the full executable path for the given executable, None otherwise """
2013-07-06 18:57:06 +05:30
full_bin = None
if os . path . exists ( bin_path ) :
full_bin = get_full_path ( bin_path )
else :
2013-07-09 03:46:26 +05:30
if ' / ' not in bin_path :
env_bin = which ( bin_path )
2013-07-06 18:57:06 +05:30
if env_bin :
full_bin = get_full_path ( env_bin )
if full_bin and os . path . exists ( full_bin ) :
return full_bin
return None
def get_profile_filename ( profile ) :
""" Returns the full profile name """
2013-08-11 15:22:07 +05:30
if existing_profiles . get ( profile , False ) :
return existing_profiles [ profile ]
elif profile . startswith ( ' / ' ) :
2013-07-06 18:57:06 +05:30
# Remove leading /
2013-07-09 03:46:26 +05:30
profile = profile [ 1 : ]
2013-07-06 18:57:06 +05:30
else :
2013-07-09 03:46:26 +05:30
profile = " profile_ " + profile
2013-08-10 12:46:22 +05:30
profile = profile . replace ( ' / ' , ' . ' )
2013-07-09 03:46:26 +05:30
full_profilename = profile_dir + ' / ' + profile
2013-07-06 18:57:06 +05:30
return full_profilename
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
def name_to_prof_filename ( prof_filename ) :
2013-07-06 18:57:06 +05:30
""" Returns the profile """
2013-07-09 03:46:26 +05:30
if prof_filename . startswith ( profile_dir ) :
profile = prof_filename . split ( profile_dir , 1 ) [ 1 ]
return ( prof_filename , profile )
2013-07-06 18:57:06 +05:30
else :
2013-07-09 03:46:26 +05:30
bin_path = find_executable ( prof_filename )
2013-07-06 18:57:06 +05:30
if bin_path :
2013-07-09 03:46:26 +05:30
prof_filename = get_profile_filename ( bin_path )
if os . path . isfile ( prof_filename ) :
return ( prof_filename , bin_path )
2013-07-06 18:57:06 +05:30
else :
return None , None
def complain ( path ) :
""" Sets the profile to complain mode if it exists """
2013-07-09 03:46:26 +05:30
prof_filename , name = name_to_prof_filename ( path )
2014-02-10 22:20:36 -08:00
if not prof_filename :
2013-09-21 01:08:34 +05:30
fatal_error ( _ ( " Can ' t find %s " ) % path )
2013-08-30 03:54:31 +05:30
set_complain ( prof_filename , name )
2013-07-06 18:57:06 +05:30
def enforce ( path ) :
2013-08-21 11:26:09 +05:30
""" Sets the profile to enforce mode if it exists """
2013-07-09 03:46:26 +05:30
prof_filename , name = name_to_prof_filename ( path )
2014-02-10 22:20:36 -08:00
if not prof_filename :
2013-09-21 01:08:34 +05:30
fatal_error ( _ ( " Can ' t find %s " ) % path )
2013-08-30 03:54:31 +05:30
set_enforce ( prof_filename , name )
2013-09-22 22:51:30 +05:30
2013-09-21 12:36:51 +05:30
def set_complain ( filename , program ) :
2013-08-30 03:54:31 +05:30
""" Sets the profile to complain mode """
2014-03-06 11:49:43 -08:00
aaui . UI_Info ( _ ( ' Setting %s to complain mode. ' ) % ( filename if program is None else program ) )
2014-02-25 13:17:46 +01:00
# a force-complain symlink is more packaging-friendly, but breaks caching
# create_symlink('force-complain', filename)
2013-09-21 12:36:51 +05:30
change_profile_flags ( filename , program , ' complain ' , True )
2013-08-30 03:54:31 +05:30
def set_enforce ( filename , program ) :
""" Sets the profile to enforce mode """
2014-03-06 11:49:43 -08:00
aaui . UI_Info ( _ ( ' Setting %s to enforce mode. ' ) % ( filename if program is None else program ) )
2013-08-30 03:54:31 +05:30
delete_symlink ( ' force-complain ' , filename )
delete_symlink ( ' disable ' , filename )
2013-09-21 12:36:51 +05:30
change_profile_flags ( filename , program , ' complain ' , False )
2013-08-30 03:54:31 +05:30
def delete_symlink ( subdir , filename ) :
path = filename
2014-02-10 22:20:36 -08:00
link = re . sub ( ' ^ %s ' % profile_dir , ' %s / %s ' % ( profile_dir , subdir ) , path )
2013-08-30 03:54:31 +05:30
if link != path and os . path . islink ( link ) :
os . remove ( link )
def create_symlink ( subdir , filename ) :
path = filename
bname = os . path . basename ( filename )
if not bname :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Unable to find basename for %s . ' ) % filename )
2013-08-31 04:08:26 +05:30
#print(filename)
2014-02-10 22:20:36 -08:00
link = re . sub ( ' ^ %s ' % profile_dir , ' %s / %s ' % ( profile_dir , subdir ) , path )
2013-08-31 04:08:26 +05:30
#print(link)
#link = link + '/%s'%bname
#print(link)
2014-02-10 22:20:36 -08:00
symlink_dir = os . path . dirname ( link )
2013-08-31 04:08:26 +05:30
if not os . path . exists ( symlink_dir ) :
# If the symlink directory does not exist create it
os . makedirs ( symlink_dir )
2013-09-22 22:51:30 +05:30
2013-08-30 03:54:31 +05:30
if not os . path . exists ( link ) :
try :
os . symlink ( filename , link )
except :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Could not create %(link)s symlink to %(file)s . ' ) % { ' link ' : link , ' file ' : filename } )
2013-09-22 22:51:30 +05:30
2013-07-06 18:57:06 +05:30
def head ( file ) :
""" Returns the first/head line of the file """
first = ' '
if os . path . isfile ( file ) :
with open_file_read ( file ) as f_in :
2013-09-21 01:08:34 +05:30
try :
first = f_in . readline ( ) . rstrip ( )
except UnicodeDecodeError :
pass
2013-08-21 11:26:09 +05:30
return first
else :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Unable to read first line from %s : File Not Found ' ) % file )
2013-07-06 18:57:06 +05:30
def get_output ( params ) :
""" Returns the return code output by running the program with the args given in the list """
program = params [ 0 ]
2014-02-13 10:01:03 -08:00
# args = params[1:]
2013-07-06 18:57:06 +05:30
ret = - 1
output = [ ]
# program is executable
if os . access ( program , os . X_OK ) :
try :
# Get the output of the program
output = subprocess . check_output ( params )
except OSError as e :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( " Unable to fork: %(program)s \n \t %(error)s " ) % { ' program ' : program , ' error ' : str ( e ) } )
2013-07-06 18:57:06 +05:30
# If exit-codes besides 0
except subprocess . CalledProcessError as e :
output = e . output
output = output . decode ( ' utf-8 ' ) . split ( ' \n ' )
ret = e . returncode
else :
ret = 0
output = output . decode ( ' utf-8 ' ) . split ( ' \n ' )
# Remove the extra empty string caused due to \n if present
if len ( output ) > 1 :
2013-09-22 22:51:30 +05:30
output . pop ( )
return ( ret , output )
2013-07-06 18:57:06 +05:30
def get_reqs ( file ) :
""" Returns a list of paths from ldd output """
pattern1 = re . compile ( ' ^ \ s* \ S+ => ( \ / \ S+) ' )
pattern2 = re . compile ( ' ^ \ s*( \ / \ S+) ' )
reqs = [ ]
2013-07-09 03:46:26 +05:30
ret , ldd_out = get_output ( [ ldd , file ] )
2013-07-06 18:57:06 +05:30
if ret == 0 :
for line in ldd_out :
if ' not a dynamic executable ' in line :
break
if ' cannot read header ' in line :
break
if ' statically linked ' in line :
break
match = pattern1 . search ( line )
if match :
reqs . append ( match . groups ( ) [ 0 ] )
else :
match = pattern2 . search ( line )
if match :
reqs . append ( match . groups ( ) [ 0 ] )
return reqs
2013-07-09 03:46:26 +05:30
def handle_binfmt ( profile , path ) :
""" Modifies the profile to add the requirements """
reqs_processed = dict ( )
reqs = get_reqs ( path )
while reqs :
library = reqs . pop ( )
if not reqs_processed . get ( library , False ) :
2013-09-21 01:08:34 +05:30
if get_reqs ( library ) :
reqs + = get_reqs ( library )
2013-07-09 03:46:26 +05:30
reqs_processed [ library ] = True
combined_mode = match_prof_incs_to_path ( profile , ' allow ' , library )
if combined_mode :
continue
library = glob_common ( library )
if not library :
continue
2013-08-11 15:22:07 +05:30
profile [ ' allow ' ] [ ' path ' ] [ library ] [ ' mode ' ] = profile [ ' allow ' ] [ ' path ' ] [ library ] . get ( ' mode ' , set ( ) ) | str_to_mode ( ' mr ' )
profile [ ' allow ' ] [ ' path ' ] [ library ] [ ' audit ' ] | = profile [ ' allow ' ] [ ' path ' ] [ library ] . get ( ' audit ' , set ( ) )
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
def get_inactive_profile ( local_profile ) :
if extras . get ( local_profile , False ) :
return { local_profile : extras [ local_profile ] }
return dict ( )
fix save_profile() by fixing some other code
When creating a child profile while using genprof, I get a backtrace:
Traceback (most recent call last):
File "aa-genprof", line 160, in <module>
lp_ret = apparmor.do_logprof_pass(logmark, passno)
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2291, in do_logprof_pass
save_profiles()
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2309, in save_profiles
for prof_name in changed.keys():
RuntimeError: dictionary changed size during iteration
(See https://bugs.launchpad.net/apparmor/+bug/1014304 for more details.)
After digging into the code, it seems for some reason the child profile
is added to "changed" - I doubt this is correct (guess why it's removed
later... ;-)
After digging a bit more, I found out that create_new_profile() is
(ab)used to create a new stub profile to be used as child profile.
create_new_profile then adds the new child (which looks like a normal
profile to it) to "changed".
This patch most probably makes the cleanup round in save_profile()
superfluous by adding a is_stub parameter to create_new_profile(). If
this parameter is set, the new (child) profile is not added to "created"
and "changed".
I intentionally added the two print() lines in safe_profile because
a) I think they will never be displayed
b) I want to know if a) is wrong ;-)
c) it's always nice to have a "nice" error message before displaying
a backtrace ;-)
Acked-by: Steve Beattie <steve@nxnw.org>
2014-06-10 00:44:59 +02:00
def create_new_profile ( localfile , is_stub = False ) :
2013-07-09 03:46:26 +05:30
local_profile = hasher ( )
local_profile [ localfile ] [ ' flags ' ] = ' complain '
2013-09-22 22:51:30 +05:30
local_profile [ localfile ] [ ' include ' ] [ ' abstractions/base ' ] = 1
2014-02-01 06:14:05 +05:30
if os . path . exists ( localfile ) and os . path . isfile ( localfile ) :
2013-07-09 03:46:26 +05:30
hashbang = head ( localfile )
if hashbang . startswith ( ' #! ' ) :
2013-07-27 15:28:12 +05:30
interpreter_path = get_full_path ( hashbang . lstrip ( ' #! ' ) . strip ( ) )
2013-09-22 22:51:30 +05:30
2013-07-27 15:32:12 +05:30
interpreter = re . sub ( ' ^(/usr)?/bin/ ' , ' ' , interpreter_path )
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] [ ' mode ' ] = local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] . get ( ' mode ' , str_to_mode ( ' r ' ) ) | str_to_mode ( ' r ' )
2013-09-22 22:51:30 +05:30
2013-08-11 15:22:07 +05:30
local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] [ ' audit ' ] = local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] . get ( ' audit ' , set ( ) )
2013-09-22 22:51:30 +05:30
local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] [ ' mode ' ] = local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] . get ( ' mode ' , str_to_mode ( ' ix ' ) ) | str_to_mode ( ' ix ' )
2013-08-11 15:22:07 +05:30
local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] [ ' audit ' ] = local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] . get ( ' audit ' , set ( ) )
2013-07-20 04:19:07 +05:30
2013-07-27 15:28:12 +05:30
if interpreter == ' perl ' :
2013-07-20 04:19:07 +05:30
local_profile [ localfile ] [ ' include ' ] [ ' abstractions/perl ' ] = True
2013-07-30 20:13:08 +05:30
elif re . search ( ' ^python([23]|[23] \ .[0-9]+)?$ ' , interpreter ) :
2013-07-20 04:19:07 +05:30
local_profile [ localfile ] [ ' include ' ] [ ' abstractions/python ' ] = True
2013-07-27 15:28:12 +05:30
elif interpreter == ' ruby ' :
2013-07-20 04:19:07 +05:30
local_profile [ localfile ] [ ' include ' ] [ ' abstractions/ruby ' ] = True
2013-07-27 15:28:12 +05:30
elif interpreter in [ ' bash ' , ' dash ' , ' sh ' ] :
2013-07-20 04:19:07 +05:30
local_profile [ localfile ] [ ' include ' ] [ ' abstractions/bash ' ] = True
2013-07-27 15:28:12 +05:30
handle_binfmt ( local_profile [ localfile ] , interpreter_path )
2013-07-09 03:46:26 +05:30
else :
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] [ ' mode ' ] = local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] . get ( ' mode ' , str_to_mode ( ' mr ' ) ) | str_to_mode ( ' mr ' )
2013-09-22 22:51:30 +05:30
2013-08-11 18:30:01 +05:30
local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] [ ' audit ' ] = local_profile [ localfile ] [ ' allow ' ] [ ' path ' ] [ localfile ] . get ( ' audit ' , set ( ) )
2013-07-20 04:19:07 +05:30
2013-07-09 03:46:26 +05:30
handle_binfmt ( local_profile [ localfile ] , localfile )
2013-09-22 22:51:30 +05:30
# Add required hats to the profile if they match the localfile
2013-07-09 03:46:26 +05:30
for hatglob in cfg [ ' required_hats ' ] . keys ( ) :
if re . search ( hatglob , localfile ) :
for hat in sorted ( cfg [ ' required_hats ' ] [ hatglob ] . split ( ) ) :
local_profile [ hat ] [ ' flags ' ] = ' complain '
2013-09-22 22:51:30 +05:30
fix save_profile() by fixing some other code
When creating a child profile while using genprof, I get a backtrace:
Traceback (most recent call last):
File "aa-genprof", line 160, in <module>
lp_ret = apparmor.do_logprof_pass(logmark, passno)
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2291, in do_logprof_pass
save_profiles()
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2309, in save_profiles
for prof_name in changed.keys():
RuntimeError: dictionary changed size during iteration
(See https://bugs.launchpad.net/apparmor/+bug/1014304 for more details.)
After digging into the code, it seems for some reason the child profile
is added to "changed" - I doubt this is correct (guess why it's removed
later... ;-)
After digging a bit more, I found out that create_new_profile() is
(ab)used to create a new stub profile to be used as child profile.
create_new_profile then adds the new child (which looks like a normal
profile to it) to "changed".
This patch most probably makes the cleanup round in save_profile()
superfluous by adding a is_stub parameter to create_new_profile(). If
this parameter is set, the new (child) profile is not added to "created"
and "changed".
I intentionally added the two print() lines in safe_profile because
a) I think they will never be displayed
b) I want to know if a) is wrong ;-)
c) it's always nice to have a "nice" error message before displaying
a backtrace ;-)
Acked-by: Steve Beattie <steve@nxnw.org>
2014-06-10 00:44:59 +02:00
if not is_stub :
created . append ( localfile )
changed [ localfile ] = True
2014-02-10 22:20:36 -08:00
2013-08-09 11:04:32 +05:30
debug_logger . debug ( " Profile for %s : \n \t %s " % ( localfile , local_profile . __str__ ( ) ) )
2013-07-09 03:46:26 +05:30
return { localfile : local_profile }
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
def delete_profile ( local_prof ) :
""" Deletes the specified file from the disk and remove it from our list """
profile_file = get_profile_filename ( local_prof )
if os . path . isfile ( profile_file ) :
os . remove ( profile_file )
if aa . get ( local_prof , False ) :
aa . pop ( local_prof )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
#prof_unload(local_prof)
def confirm_and_abort ( ) :
2014-02-10 22:17:21 -08:00
ans = aaui . UI_YesNo ( _ ( ' Are you sure you want to abandon this set of profile changes and exit? ' ) , ' n ' )
2013-07-31 19:56:33 +05:30
if ans == ' y ' :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Abandoning all changes. ' ) )
2013-07-31 19:56:33 +05:30
shutdown_yast ( )
for prof in created :
delete_profile ( prof )
sys . exit ( 0 )
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
def get_profile ( prof_name ) :
profile_data = None
distro = cfg [ ' repository ' ] [ ' distro ' ]
repo_url = cfg [ ' repository ' ] [ ' url ' ]
2014-02-13 10:01:03 -08:00
# local_profiles = []
2013-07-09 03:46:26 +05:30
profile_hash = hasher ( )
if repo_is_enabled ( ) :
2014-02-10 22:17:21 -08:00
aaui . UI_BusyStart ( _ ( ' Connecting to repository... ' ) )
2013-07-09 03:46:26 +05:30
status_ok , ret = fetch_profiles_by_name ( repo_url , distro , prof_name )
2014-02-10 22:17:21 -08:00
aaui . UI_BusyStop ( )
2013-07-09 03:46:26 +05:30
if status_ok :
profile_hash = ret
else :
2014-02-10 22:17:21 -08:00
aaui . UI_Important ( _ ( ' WARNING: Error fetching profiles from the repository ' ) )
2013-07-09 03:46:26 +05:30
inactive_profile = get_inactive_profile ( prof_name )
if inactive_profile :
uname = ' Inactive local profile for %s ' % prof_name
inactive_profile [ prof_name ] [ prof_name ] [ ' flags ' ] = ' complain '
inactive_profile [ prof_name ] [ prof_name ] . pop ( ' filename ' )
profile_hash [ uname ] [ ' username ' ] = uname
profile_hash [ uname ] [ ' profile_type ' ] = ' INACTIVE_LOCAL '
profile_hash [ uname ] [ ' profile ' ] = serialize_profile ( inactive_profile [ prof_name ] , prof_name )
profile_hash [ uname ] [ ' profile_data ' ] = inactive_profile
# If no profiles in repo and no inactive profiles
if not profile_hash . keys ( ) :
return None
options = [ ]
tmp_list = [ ]
preferred_present = False
preferred_user = cfg [ ' repository ' ] . get ( ' preferred_user ' , ' NOVELL ' )
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
for p in profile_hash . keys ( ) :
if profile_hash [ p ] [ ' username ' ] == preferred_user :
preferred_present = True
else :
tmp_list . append ( profile_hash [ p ] [ ' username ' ] )
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
if preferred_present :
options . append ( preferred_user )
options + = tmp_list
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
q . headers = [ ' Profile ' , prof_name ]
q . functions = [ ' CMD_VIEW_PROFILE ' , ' CMD_USE_PROFILE ' , ' CMD_CREATE_PROFILE ' ,
2013-07-09 03:46:26 +05:30
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2014-10-07 18:36:01 +05:30
q . default = " CMD_VIEW_PROFILE "
q . options = options
q . selected = 0
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
ans = ' '
while ' CMD_USE_PROFILE ' not in ans and ' CMD_CREATE_PROFILE ' not in ans :
2014-02-24 20:56:28 +01:00
if ans == ' CMD_FINISHED ' :
save_profiles ( )
return
2014-10-07 18:36:01 +05:30
ans , arg = q . promptUser ( )
2013-07-09 03:46:26 +05:30
p = profile_hash [ options [ arg ] ]
2014-10-07 18:36:01 +05:30
q . selected = options . index ( options [ arg ] )
2013-07-09 03:46:26 +05:30
if ans == ' CMD_VIEW_PROFILE ' :
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
2014-02-10 22:20:36 -08:00
SendDataToYast ( { ' type ' : ' dialogue-view-profile ' ,
2013-07-09 03:46:26 +05:30
' user ' : options [ arg ] ,
' profile ' : p [ ' profile ' ] ,
' profile_type ' : p [ ' profile_type ' ]
} )
ypath , yarg = GetDataFromYast ( )
2013-07-28 08:23:46 +05:30
#else:
# pager = get_pager()
# proc = subprocess.Popen(pager, stdin=subprocess.PIPE)
2013-09-22 22:51:30 +05:30
# proc.communicate('Profile submitted by %s:\n\n%s\n\n' %
2013-07-28 08:23:46 +05:30
# (options[arg], p['profile']))
# proc.kill()
2013-07-09 03:46:26 +05:30
elif ans == ' CMD_USE_PROFILE ' :
if p [ ' profile_type ' ] == ' INACTIVE_LOCAL ' :
profile_data = p [ ' profile_data ' ]
created . append ( prof_name )
else :
profile_data = parse_repo_profile ( prof_name , repo_url , p )
return profile_data
def activate_repo_profiles ( url , profiles , complain ) :
read_profiles ( )
try :
for p in profiles :
pname = p [ 0 ]
profile_data = parse_repo_profile ( pname , url , p [ 1 ] )
attach_profile_data ( aa , profile_data )
write_profile ( pname )
if complain :
fname = get_profile_filename ( pname )
2013-08-31 04:08:26 +05:30
set_profile_flags ( profile_dir + fname , ' complain ' )
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Setting %s to complain mode. ' ) % pname )
2013-07-09 03:46:26 +05:30
except Exception as e :
2013-09-20 19:20:41 +05:30
sys . stderr . write ( _ ( " Error activating profiles: %s " ) % e )
2013-07-09 03:46:26 +05:30
def autodep ( bin_name , pname = ' ' ) :
bin_full = None
2013-09-21 01:08:34 +05:30
global repo_cfg
2013-07-09 03:46:26 +05:30
if not bin_name and pname . startswith ( ' / ' ) :
bin_name = pname
if not repo_cfg and not cfg [ ' repository ' ] . get ( ' url ' , False ) :
2013-08-21 11:26:09 +05:30
repo_conf = apparmor . config . Config ( ' shell ' , CONFDIR )
2013-07-31 19:56:33 +05:30
repo_cfg = repo_conf . read_config ( ' repository.conf ' )
2013-07-09 03:46:26 +05:30
if not repo_cfg . get ( ' repository ' , False ) or repo_cfg [ ' repository ' ] [ ' enabled ' ] == ' later ' :
UI_ask_to_enable_repo ( )
if bin_name :
bin_full = find_executable ( bin_name )
#if not bin_full:
# bin_full = bin_name
#if not bin_full.startswith('/'):
#return None
# Return if exectuable path not found
if not bin_full :
return None
2014-02-01 06:14:05 +05:30
else :
bin_full = pname # for named profiles
2013-07-09 03:46:26 +05:30
pname = bin_full
2013-07-31 19:56:33 +05:30
read_inactive_profiles ( )
2013-07-09 03:46:26 +05:30
profile_data = get_profile ( pname )
# Create a new profile if no existing profile
if not profile_data :
profile_data = create_new_profile ( pname )
file = get_profile_filename ( pname )
attach_profile_data ( aa , profile_data )
2013-07-28 08:23:46 +05:30
attach_profile_data ( original_aa , profile_data )
2013-07-09 03:46:26 +05:30
if os . path . isfile ( profile_dir + ' /tunables/global ' ) :
if not filelist . get ( file , False ) :
2013-09-21 01:08:34 +05:30
filelist [ file ] = hasher ( )
filelist [ file ] [ ' include ' ] [ ' tunables/global ' ] = True
2014-05-22 19:43:10 +02:00
filelist [ file ] [ ' profiles ' ] [ pname ] = hasher ( )
filelist [ file ] [ ' profiles ' ] [ pname ] [ pname ] = True
2013-07-09 03:46:26 +05:30
write_profile_ui_feedback ( pname )
2013-08-21 11:26:09 +05:30
2013-09-21 12:36:51 +05:30
def get_profile_flags ( filename , program ) :
2013-08-26 00:23:59 +05:30
# To-Do
# XXX If more than one profile in a file then second one is being ignored XXX
2013-09-22 22:51:30 +05:30
# Do we return flags for both or
2013-08-26 00:23:59 +05:30
flags = ' '
2013-08-21 11:26:09 +05:30
with open_file_read ( filename ) as f_in :
for line in f_in :
if RE_PROFILE_START . search ( line ) :
2015-04-13 18:24:20 -07:00
matches = parse_profile_start_line ( line , filename )
profile = matches [ ' profile ' ]
flags = matches [ ' flags ' ]
2014-03-06 11:49:43 -08:00
if profile == program or program is None :
2013-09-21 12:36:51 +05:30
return flags
2013-08-26 00:23:59 +05:30
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' %s contains no profile ' ) % filename )
2013-09-22 22:51:30 +05:30
2013-09-21 12:36:51 +05:30
def change_profile_flags ( filename , program , flag , set_flag ) :
old_flags = get_profile_flags ( filename , program )
2013-08-26 00:23:59 +05:30
newflags = [ ]
2013-08-31 04:08:26 +05:30
if old_flags :
2013-08-26 00:23:59 +05:30
# Flags maybe white-space and/or , separated
old_flags = old_flags . split ( ' , ' )
2014-02-10 22:20:36 -08:00
if not isinstance ( old_flags , str ) :
2013-08-26 00:23:59 +05:30
for i in old_flags :
newflags + = i . split ( )
else :
newflags = old_flags . split ( )
#newflags = [lambda x:x.strip(), oldflags]
2013-09-22 22:51:30 +05:30
2013-08-30 03:54:31 +05:30
if set_flag :
if flag not in newflags :
newflags . append ( flag )
2013-08-26 00:23:59 +05:30
else :
2013-08-30 03:54:31 +05:30
if flag in newflags :
newflags . remove ( flag )
2013-08-26 00:23:59 +05:30
newflags = ' , ' . join ( newflags )
2013-08-31 04:08:26 +05:30
2013-09-22 22:51:30 +05:30
set_profile_flags ( filename , program , newflags )
2013-09-21 12:36:51 +05:30
def set_profile_flags ( prof_filename , program , newflags ) :
2013-07-09 03:46:26 +05:30
""" Reads the old profile file and updates the flags accordingly """
2014-06-19 20:44:57 +02:00
regex_bin_flag = re . compile ( ' ^( \ s*)( " ?(/.+?) " ??|(profile \ s+ " ?(.+?) " ??)) \ s+((flags=)? \ ((.*) \ ) \ s+)? \ { \ s*(#.*)?$ ' )
# TODO: use RE_PROFILE_START (only difference: doesn't have a match group for the leading space)
# TODO: also use the global regex for matching the hat
# TODO: count the number of matching lines (separated by profile and hat?) and return it
# so that code calling this function can make sure to only report success if there was a match
2013-08-10 12:46:22 +05:30
regex_hat_flag = re . compile ( ' ^([a-z]*) \ s+([A-Z]*) \ s*(#.*)?$ ' )
2013-07-09 03:46:26 +05:30
if os . path . isfile ( prof_filename ) :
with open_file_read ( prof_filename ) as f_in :
2014-02-10 22:20:36 -08:00
temp_file = tempfile . NamedTemporaryFile ( ' w ' , prefix = prof_filename , suffix = ' ~ ' , delete = False , dir = profile_dir )
2013-08-31 04:08:26 +05:30
shutil . copymode ( prof_filename , temp_file . name )
with open_file_write ( temp_file . name ) as f_out :
2013-07-09 03:46:26 +05:30
for line in f_in :
2013-08-10 12:46:22 +05:30
comment = ' '
2013-07-17 20:38:13 +05:30
if ' # ' in line :
comment = ' # ' + line . split ( ' # ' , 1 ) [ 1 ] . rstrip ( )
2013-07-09 03:46:26 +05:30
match = regex_bin_flag . search ( line )
2013-08-31 04:08:26 +05:30
if not line . strip ( ) or line . strip ( ) . startswith ( ' # ' ) :
pass
elif match :
2013-08-10 12:46:22 +05:30
matches = match . groups ( )
space = matches [ 0 ]
2014-06-19 20:44:57 +02:00
profile = matches [ 1 ] # profile name including quotes and "profile" keyword
if matches [ 2 ] :
binary = matches [ 2 ]
else :
binary = matches [ 4 ]
2013-08-31 04:08:26 +05:30
flag = matches [ 6 ] or ' flags= '
2013-08-10 12:46:22 +05:30
flags = matches [ 7 ]
2014-03-06 11:49:43 -08:00
if binary == program or program is None :
2013-09-21 12:36:51 +05:30
if newflags :
2014-06-19 20:44:57 +02:00
line = ' %s %s %s ( %s ) { %s \n ' % ( space , profile , flag , newflags , comment )
2013-09-21 12:36:51 +05:30
else :
2014-06-19 20:44:57 +02:00
line = ' %s %s { %s \n ' % ( space , profile , comment )
2013-07-09 03:46:26 +05:30
else :
match = regex_hat_flag . search ( line )
if match :
2013-08-31 04:08:26 +05:30
hat , flags = match . groups ( ) [ : 2 ]
2013-07-09 03:46:26 +05:30
if newflags :
2013-07-17 20:38:13 +05:30
line = ' %s flags=( %s ) { %s \n ' % ( hat , newflags , comment )
2013-07-09 03:46:26 +05:30
else :
2013-07-17 20:38:13 +05:30
line = ' %s { %s \n ' % ( hat , comment )
2013-07-09 03:46:26 +05:30
f_out . write ( line )
2013-08-31 04:08:26 +05:30
os . rename ( temp_file . name , prof_filename )
2013-07-09 03:46:26 +05:30
def profile_exists ( program ) :
""" Returns True if profile exists, False otherwise """
# Check cache of profiles
2013-09-22 22:51:30 +05:30
2013-07-09 03:46:26 +05:30
if existing_profiles . get ( program , False ) :
return True
# Check the disk for profile
prof_path = get_profile_filename ( program )
2013-08-10 12:46:22 +05:30
#print(prof_path)
2013-07-09 03:46:26 +05:30
if os . path . isfile ( prof_path ) :
# Add to cache of profile
2013-08-11 15:22:07 +05:30
existing_profiles [ program ] = prof_path
2013-07-09 03:46:26 +05:30
return True
return False
2013-07-17 20:38:13 +05:30
def sync_profile ( ) :
user , passw = get_repo_user_pass ( )
if not user or not passw :
return None
repo_profiles = [ ]
changed_profiles = [ ]
new_profiles = [ ]
serialize_opts = hasher ( )
status_ok , ret = fetch_profiles_by_user ( cfg [ ' repository ' ] [ ' url ' ] ,
cfg [ ' repository ' ] [ ' distro ' ] , user )
if not status_ok :
if not ret :
ret = ' UNKNOWN ERROR '
2014-02-10 22:17:21 -08:00
aaui . UI_Important ( _ ( ' WARNING: Error synchronizing profiles with the repository: \n %s \n ' ) % ret )
2013-07-17 20:38:13 +05:30
else :
users_repo_profiles = ret
2013-07-27 15:28:12 +05:30
serialize_opts [ ' NO_FLAGS ' ] = True
2013-07-17 20:38:13 +05:30
for prof in sorted ( aa . keys ( ) ) :
if is_repo_profile ( [ aa [ prof ] [ prof ] ] ) :
repo_profiles . append ( prof )
if prof in created :
2013-07-27 15:28:12 +05:30
p_local = serialize_profile ( aa [ prof ] , prof , serialize_opts )
2013-07-17 20:38:13 +05:30
if not users_repo_profiles . get ( prof , False ) :
new_profiles . append ( prof )
new_profiles . append ( p_local )
new_profiles . append ( ' ' )
else :
p_repo = users_repo_profiles [ prof ] [ ' profile ' ]
if p_local != p_repo :
changed_profiles . append ( prof )
changed_profiles . append ( p_local )
changed_profiles . append ( p_repo )
if repo_profiles :
for prof in repo_profiles :
p_local = serialize_profile ( aa [ prof ] , prof , serialize_opts )
if not users_repo_profiles . get ( prof , False ) :
new_profiles . append ( prof )
new_profiles . append ( p_local )
new_profiles . append ( ' ' )
else :
p_repo = ' '
if aa [ prof ] [ prof ] [ ' repo ' ] [ ' user ' ] == user :
p_repo = users_repo_profiles [ prof ] [ ' profile ' ]
else :
status_ok , ret = fetch_profile_by_id ( cfg [ ' repository ' ] [ ' url ' ] ,
aa [ prof ] [ prof ] [ ' repo ' ] [ ' id ' ] )
if status_ok :
p_repo = ret [ ' profile ' ]
else :
if not ret :
ret = ' UNKNOWN ERROR '
2014-02-10 22:17:21 -08:00
aaui . UI_Important ( _ ( ' WARNING: Error synchronizing profiles with the repository \n %s ' ) % ret )
2013-07-17 20:38:13 +05:30
continue
if p_repo != p_local :
changed_profiles . append ( prof )
changed_profiles . append ( p_local )
changed_profiles . append ( p_repo )
if changed_profiles :
submit_changed_profiles ( changed_profiles )
if new_profiles :
submit_created_profiles ( new_profiles )
2013-07-31 19:56:33 +05:30
def fetch_profile_by_id ( url , id ) :
#To-Do
return None , None
def fetch_profiles_by_name ( url , distro , user ) :
#to-Do
return None , None
def fetch_profiles_by_user ( url , distro , user ) :
#to-Do
return None , None
2013-07-17 20:38:13 +05:30
def submit_created_profiles ( new_profiles ) :
#url = cfg['repository']['url']
if new_profiles :
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
2013-07-17 20:38:13 +05:30
title = ' New Profiles '
message = ' Please select the newly created profiles that you would like to store in the repository '
yast_select_and_upload_profiles ( title , message , new_profiles )
else :
title = ' Submit newly created profiles to the repository '
message = ' Would you like to upload newly created profiles? '
console_select_and_upload_profiles ( title , message , new_profiles )
def submit_changed_profiles ( changed_profiles ) :
#url = cfg['repository']['url']
if changed_profiles :
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
2013-07-17 20:38:13 +05:30
title = ' Changed Profiles '
message = ' Please select which of the changed profiles would you like to upload to the repository '
yast_select_and_upload_profiles ( title , message , changed_profiles )
else :
title = ' Submit changed profiles to the repository '
message = ' The following profiles from the repository were changed. \n Would you like to upload your changes? '
console_select_and_upload_profiles ( title , message , changed_profiles )
def yast_select_and_upload_profiles ( title , message , profiles_up ) :
url = cfg [ ' repository ' ] [ ' url ' ]
profile_changes = hasher ( )
profs = profiles_up [ : ]
for p in profs :
profile_changes [ p [ 0 ] ] = get_profile_diff ( p [ 2 ] , p [ 1 ] )
2014-02-10 22:20:36 -08:00
SendDataToYast ( { ' type ' : ' dialog-select-profiles ' ,
2013-07-17 20:38:13 +05:30
' title ' : title ,
' explanation ' : message ,
' default_select ' : ' false ' ,
' disable_ask_upload ' : ' true ' ,
' profiles ' : profile_changes
} )
ypath , yarg = GetDataFromYast ( )
selected_profiles = [ ]
changelog = None
changelogs = None
single_changelog = False
if yarg [ ' STATUS ' ] == ' cancel ' :
return
else :
selected_profiles = yarg [ ' PROFILES ' ]
changelogs = yarg [ ' CHANGELOG ' ]
if changelogs . get ( ' SINGLE_CHANGELOG ' , False ) :
changelog = changelogs [ ' SINGLE_CHANGELOG ' ]
single_changelog = True
user , passw = get_repo_user_pass ( )
for p in selected_profiles :
profile_string = serialize_profile ( aa [ p ] , p )
if not single_changelog :
changelog = changelogs [ p ]
status_ok , ret = upload_profile ( url , user , passw , cfg [ ' repository ' ] [ ' distro ' ] ,
p , profile_string , changelog )
if status_ok :
newprofile = ret
newid = newprofile [ ' id ' ]
set_repo_info ( aa [ p ] [ p ] , url , user , newid )
write_profile_ui_feedback ( p )
else :
if not ret :
ret = ' UNKNOWN ERROR '
2014-09-14 23:47:00 +05:30
aaui . UI_Important ( _ ( ' WARNING: An error occurred while uploading the profile %(profile)s \n %(ret)s ' ) % { ' profile ' : p , ' ret ' : ret } )
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Uploaded changes to repository. ' ) )
2013-07-17 20:38:13 +05:30
if yarg . get ( ' NEVER_ASK_AGAIN ' ) :
unselected_profiles = [ ]
for p in profs :
if p [ 0 ] not in selected_profiles :
unselected_profiles . append ( p [ 0 ] )
set_profiles_local_only ( unselected_profiles )
2013-08-01 21:57:27 +05:30
def upload_profile ( url , user , passw , distro , p , profile_string , changelog ) :
# To-Do
return None , None
2013-07-17 20:38:13 +05:30
def console_select_and_upload_profiles ( title , message , profiles_up ) :
url = cfg [ ' repository ' ] [ ' url ' ]
profs = profiles_up [ : ]
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
q . title = title
q . headers = [ ' Repository ' , url ]
q . explanation = message
2014-10-08 10:41:31 -07:00
q . functions = [ ' CMD_UPLOAD_CHANGES ' , ' CMD_VIEW_CHANGES ' , ' CMD_ASK_LATER ' ,
2013-07-17 20:38:13 +05:30
' CMD_ASK_NEVER ' , ' CMD_ABORT ' ]
2014-10-07 18:36:01 +05:30
q . default = ' CMD_VIEW_CHANGES '
q . options = [ i [ 0 ] for i in profs ]
q . selected = 0
2013-07-17 20:38:13 +05:30
ans = ' '
while ' CMD_UPLOAD_CHANGES ' not in ans and ' CMD_ASK_NEVER ' not in ans and ' CMD_ASK_LATER ' not in ans :
2014-10-07 18:36:01 +05:30
ans , arg = q . promptUser ( )
2013-07-17 20:38:13 +05:30
if ans == ' CMD_VIEW_CHANGES ' :
display_changes ( profs [ arg ] [ 2 ] , profs [ arg ] [ 1 ] )
if ans == ' CMD_NEVER_ASK ' :
set_profiles_local_only ( [ i [ 0 ] for i in profs ] )
elif ans == ' CMD_UPLOAD_CHANGES ' :
2014-02-10 22:17:21 -08:00
changelog = aaui . UI_GetString ( _ ( ' Changelog Entry: ' ) , ' ' )
2013-07-17 20:38:13 +05:30
user , passw = get_repo_user_pass ( )
if user and passw :
for p_data in profs :
prof = p_data [ 0 ]
prof_string = p_data [ 1 ]
2013-09-22 22:51:30 +05:30
status_ok , ret = upload_profile ( url , user , passw ,
2013-07-17 20:38:13 +05:30
cfg [ ' repository ' ] [ ' distro ' ] ,
2014-02-10 22:20:36 -08:00
prof , prof_string , changelog )
2013-07-17 20:38:13 +05:30
if status_ok :
newprof = ret
newid = newprof [ ' id ' ]
set_repo_info ( aa [ prof ] [ prof ] , url , user , newid )
write_profile_ui_feedback ( prof )
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( ' Uploaded %s to repository ' % prof )
2013-07-17 20:38:13 +05:30
else :
if not ret :
ret = ' UNKNOWN ERROR '
2014-09-14 23:47:00 +05:30
aaui . UI_Important ( _ ( ' WARNING: An error occurred while uploading the profile %(profile)s \n %(ret)s ' ) % { ' profile ' : prof , ' ret ' : ret } )
2013-07-17 20:38:13 +05:30
else :
2014-02-10 22:17:21 -08:00
aaui . UI_Important ( _ ( ' Repository Error \n Registration or Signin was unsuccessful. User login \n information is required to upload profiles to the repository. \n These changes could not be sent. ' ) )
2013-07-17 20:38:13 +05:30
2013-07-31 19:56:33 +05:30
def set_profiles_local_only ( profs ) :
2013-07-17 20:38:13 +05:30
for p in profs :
aa [ profs ] [ profs ] [ ' repo ' ] [ ' neversubmit ' ] = True
2013-07-31 19:56:33 +05:30
write_profile_ui_feedback ( profs )
2013-07-17 20:38:13 +05:30
def build_x_functions ( default , options , exec_toggle ) :
ret_list = [ ]
2014-02-01 06:14:05 +05:30
fallback_toggle = False
2013-07-17 20:38:13 +05:30
if exec_toggle :
if ' i ' in options :
ret_list . append ( ' CMD_ix ' )
if ' p ' in options :
ret_list . append ( ' CMD_pix ' )
2014-02-01 06:14:05 +05:30
fallback_toggle = True
if ' c ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_cix ' )
2014-02-01 06:14:05 +05:30
fallback_toggle = True
if ' n ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_nix ' )
2014-02-01 06:14:05 +05:30
fallback_toggle = True
if fallback_toggle :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_EXEC_IX_OFF ' )
2014-02-01 06:14:05 +05:30
if ' u ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_ux ' )
2014-02-10 22:20:36 -08:00
2013-07-17 20:38:13 +05:30
else :
if ' i ' in options :
ret_list . append ( ' CMD_ix ' )
2014-02-01 06:14:05 +05:30
if ' c ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_cx ' )
2014-02-01 06:14:05 +05:30
fallback_toggle = True
if ' p ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_px ' )
2014-02-01 06:14:05 +05:30
fallback_toggle = True
if ' n ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_nx ' )
2014-02-01 06:14:05 +05:30
fallback_toggle = True
if ' u ' in options :
2013-07-17 20:38:13 +05:30
ret_list . append ( ' CMD_ux ' )
2014-02-01 06:14:05 +05:30
if fallback_toggle :
ret_list . append ( ' CMD_EXEC_IX_ON ' )
2013-07-17 20:38:13 +05:30
ret_list + = [ ' CMD_DENY ' , ' CMD_ABORT ' , ' CMD_FINISHED ' ]
return ret_list
def handle_children ( profile , hat , root ) :
entries = root [ : ]
2013-07-23 04:35:51 +05:30
pid = None
p = None
h = None
prog = None
aamode = None
mode = None
detail = None
to_name = None
uhat = None
capability = None
family = None
sock_type = None
protocol = None
2013-10-01 01:30:50 +05:30
global seen_events
2013-07-23 04:35:51 +05:30
regex_nullcomplain = re . compile ( ' ^null(-complain)*-profile$ ' )
2013-09-22 22:51:30 +05:30
2013-07-17 20:38:13 +05:30
for entry in entries :
2013-07-20 04:19:07 +05:30
if type ( entry [ 0 ] ) != str :
handle_children ( profile , hat , entry )
else :
typ = entry . pop ( 0 )
if typ == ' fork ' :
2013-08-21 11:26:09 +05:30
# If type is fork then we (should) have pid, profile and hat
2013-07-20 04:19:07 +05:30
pid , p , h = entry [ : 3 ]
if not regex_nullcomplain . search ( p ) and not regex_nullcomplain . search ( h ) :
profile = p
hat = h
if hat :
profile_changes [ pid ] = profile + ' // ' + hat
else :
profile_changes [ pid ] = profile
2013-08-11 15:22:07 +05:30
elif typ == ' unknown_hat ' :
2013-08-21 11:26:09 +05:30
# If hat is not known then we (should) have pid, profile, hat, mode and unknown hat in entry
2013-07-20 04:19:07 +05:30
pid , p , h , aamode , uhat = entry [ : 5 ]
if not regex_nullcomplain . search ( p ) :
profile = p
if aa [ profile ] . get ( uhat , False ) :
hat = uhat
continue
new_p = update_repo_profile ( aa [ profile ] [ profile ] )
if new_p and UI_SelectUpdatedRepoProfile ( profile , new_p ) and aa [ profile ] . get ( uhat , False ) :
hat = uhat
continue
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
default_hat = None
for hatglob in cfg . options ( ' defaulthat ' ) :
if re . search ( hatglob , profile ) :
default_hat = cfg [ ' defaulthat ' ] [ hatglob ]
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
context = profile
context = context + ' -> ^ %s ' % uhat
ans = transitions . get ( context , ' XXXINVALIDXXX ' )
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
while ans not in [ ' CMD_ADDHAT ' , ' CMD_USEDEFAULT ' , ' CMD_DENY ' ] :
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
q . headers + = [ _ ( ' Profile ' ) , profile ]
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if default_hat :
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Default Hat ' ) , default_hat ]
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Requested Hat ' ) , uhat ]
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . functions . append ( ' CMD_ADDHAT ' )
2013-07-20 04:19:07 +05:30
if default_hat :
2014-10-07 18:36:01 +05:30
q . functions . append ( ' CMD_USEDEFAULT ' )
q . functions + = [ ' CMD_DENY ' , ' CMD_ABORT ' , ' CMD_FINISHED ' ]
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . default = ' CMD_DENY '
2013-07-20 04:19:07 +05:30
if aamode == ' PERMITTING ' :
2014-10-07 18:36:01 +05:30
q . default = ' CMD_ADDHAT '
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
seen_events + = 1
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
ans = q . promptUser ( )
2013-09-22 22:51:30 +05:30
2014-02-24 20:56:28 +01:00
if ans == ' CMD_FINISHED ' :
save_profiles ( )
return
2013-07-20 04:19:07 +05:30
transitions [ context ] = ans
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if ans == ' CMD_ADDHAT ' :
hat = uhat
aa [ profile ] [ hat ] [ ' flags ' ] = aa [ profile ] [ profile ] [ ' flags ' ]
elif ans == ' CMD_USEDEFAULT ' :
hat = default_hat
elif ans == ' CMD_DENY ' :
2013-08-21 11:26:09 +05:30
# As unknown hat is denied no entry for it should be made
2013-07-20 04:19:07 +05:30
return None
2013-09-22 22:51:30 +05:30
2013-08-11 15:22:07 +05:30
elif typ == ' capability ' :
2013-08-21 11:26:09 +05:30
# If capability then we (should) have pid, profile, hat, program, mode, capability
2013-07-20 04:19:07 +05:30
pid , p , h , prog , aamode , capability = entry [ : 6 ]
if not regex_nullcomplain . search ( p ) and not regex_nullcomplain . search ( h ) :
profile = p
hat = h
if not profile or not hat :
continue
prelog [ aamode ] [ profile ] [ hat ] [ ' capability ' ] [ capability ] = True
2013-09-22 22:51:30 +05:30
2013-08-11 15:22:07 +05:30
elif typ == ' path ' or typ == ' exec ' :
2013-08-21 11:26:09 +05:30
# If path or exec then we (should) have pid, profile, hat, program, mode, details and to_name
2013-07-20 04:19:07 +05:30
pid , p , h , prog , aamode , mode , detail , to_name = entry [ : 8 ]
if not mode :
2013-08-11 18:30:01 +05:30
mode = set ( )
2013-07-20 04:19:07 +05:30
if not regex_nullcomplain . search ( p ) and not regex_nullcomplain . search ( h ) :
profile = p
hat = h
if not profile or not hat or not detail :
continue
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
domainchange = ' nochange '
2013-08-11 15:22:07 +05:30
if typ == ' exec ' :
2013-07-20 04:19:07 +05:30
domainchange = ' change '
# Escape special characters
detail = detail . replace ( ' [ ' , ' \ [ ' )
detail = detail . replace ( ' ] ' , ' \ ] ' )
detail = detail . replace ( ' + ' , ' \ + ' )
detail = detail . replace ( ' * ' , ' \ * ' )
detail = detail . replace ( ' { ' , ' \ { ' )
detail = detail . replace ( ' } ' , ' \ } ' )
2013-09-22 22:51:30 +05:30
# Give Execute dialog if x access requested for something that's not a directory
2013-07-20 04:19:07 +05:30
# For directories force an 'ix' Path dialog
do_execute = False
exec_target = detail
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if mode & str_to_mode ( ' x ' ) :
if os . path . isdir ( exec_target ) :
2013-08-11 23:16:05 +05:30
mode = mode - apparmor . aamode . ALL_AA_EXEC_TYPE
2013-07-20 04:19:07 +05:30
mode = mode | str_to_mode ( ' ix ' )
else :
do_execute = True
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
if mode & apparmor . aamode . AA_MAY_LINK :
2013-07-20 04:19:07 +05:30
regex_link = re . compile ( ' ^from (.+) to (.+)$ ' )
match = regex_link . search ( detail )
if match :
path = match . groups ( ) [ 0 ]
target = match . groups ( ) [ 1 ]
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
frommode = str_to_mode ( ' lr ' )
if prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] . get ( path , False ) :
frommode | = prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ]
prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ] = frommode
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
tomode = str_to_mode ( ' lr ' )
if prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] . get ( target , False ) :
tomode | = prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ target ]
2013-09-22 22:51:30 +05:30
prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ target ] = tomode
2013-07-20 04:19:07 +05:30
else :
continue
elif mode :
path = detail
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] . get ( path , False ) :
mode | = prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ]
prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ] = mode
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if do_execute :
if profile_known_exec ( aa [ profile ] [ hat ] , ' exec ' , exec_target ) :
continue
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
p = update_repo_profile ( aa [ profile ] [ profile ] )
if to_name :
if UI_SelectUpdatedRepoProfile ( profile , p ) and profile_known_exec ( aa [ profile ] [ hat ] , ' exec ' , to_name ) :
continue
else :
if UI_SelectUpdatedRepoProfile ( profile , p ) and profile_known_exec ( aa [ profile ] [ hat ] , ' exec ' , exec_target ) :
continue
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
context_new = profile
if profile != hat :
context_new = context_new + ' ^ %s ' % hat
2013-10-01 01:30:50 +05:30
context_new = context_new + ' -> %s ' % exec_target
2013-09-22 22:51:30 +05:30
2014-02-13 10:52:00 -08:00
# ans_new = transitions.get(context_new, '') # XXX ans meant here?
2013-08-11 18:30:01 +05:30
combinedmode = set ( )
combinedaudit = set ( )
2013-07-23 04:35:51 +05:30
## Check return Value Consistency
2013-07-20 04:19:07 +05:30
# Check if path matches any existing regexps in profile
2014-02-10 22:20:36 -08:00
cm , am , m = rematchfrag ( aa [ profile ] [ hat ] , ' allow ' , exec_target )
2013-07-20 04:19:07 +05:30
if cm :
combinedmode | = cm
if am :
combinedaudit | = am
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if combinedmode & str_to_mode ( ' x ' ) :
nt_name = None
for entr in m :
if aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] . get ( entr , False ) :
2014-08-26 03:13:42 +05:30
nt_name = entr
2013-07-20 04:19:07 +05:30
break
2013-07-23 04:35:51 +05:30
if to_name and to_name != nt_name :
pass
elif nt_name :
to_name = nt_name
## Check return value consistency
# Check if the includes from profile match
cm , am , m = match_prof_incs_to_path ( aa [ profile ] [ hat ] , ' allow ' , exec_target )
if cm :
combinedmode | = cm
if am :
combinedaudit | = am
if combinedmode & str_to_mode ( ' x ' ) :
nt_name = None
for entr in m :
if aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ entry ] [ ' to ' ] :
2014-02-13 10:52:00 -08:00
nt_name = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ entry ] [ ' to ' ]
2013-07-23 04:35:51 +05:30
break
if to_name and to_name != nt_name :
2013-07-20 04:19:07 +05:30
pass
elif nt_name :
to_name = nt_name
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
# nx is not used in profiles but in log files.
# Log parsing methods will convert it to its profile form
# nx is internally cx/px/cix/pix + to_name
exec_mode = False
if contains ( combinedmode , ' pix ' ) :
if to_name :
ans = ' CMD_nix '
else :
ans = ' CMD_pix '
exec_mode = str_to_mode ( ' pixr ' )
elif contains ( combinedmode , ' cix ' ) :
if to_name :
ans = ' CMD_nix '
else :
ans = ' CMD_cix '
exec_mode = str_to_mode ( ' cixr ' )
elif contains ( combinedmode , ' Pix ' ) :
if to_name :
ans = ' CMD_nix_safe '
else :
ans = ' CMD_pix_safe '
exec_mode = str_to_mode ( ' Pixr ' )
elif contains ( combinedmode , ' Cix ' ) :
if to_name :
ans = ' CMD_nix_safe '
else :
ans = ' CMD_cix_safe '
exec_mode = str_to_mode ( ' Cixr ' )
elif contains ( combinedmode , ' ix ' ) :
ans = ' CMD_ix '
exec_mode = str_to_mode ( ' ixr ' )
elif contains ( combinedmode , ' px ' ) :
if to_name :
ans = ' CMD_nx '
else :
ans = ' CMD_px '
exec_mode = str_to_mode ( ' px ' )
elif contains ( combinedmode , ' cx ' ) :
if to_name :
ans = ' CMD_nx '
else :
ans = ' CMD_cx '
exec_mode = str_to_mode ( ' cx ' )
elif contains ( combinedmode , ' ux ' ) :
ans = ' CMD_ux '
exec_mode = str_to_mode ( ' ux ' )
elif contains ( combinedmode , ' Px ' ) :
if to_name :
ans = ' CMD_nx_safe '
else :
ans = ' CMD_px_safe '
exec_mode = str_to_mode ( ' Px ' )
elif contains ( combinedmode , ' Cx ' ) :
if to_name :
ans = ' CMD_nx_safe '
else :
ans = ' CMD_cx_safe '
exec_mode = str_to_mode ( ' Cx ' )
elif contains ( combinedmode , ' Ux ' ) :
ans = ' CMD_ux_safe '
exec_mode = str_to_mode ( ' Ux ' )
else :
options = cfg [ ' qualifiers ' ] . get ( exec_target , ' ipcnu ' )
if to_name :
2013-09-21 01:08:34 +05:30
fatal_error ( _ ( ' %s has transition name but not transition mode ' ) % entry )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
### If profiled program executes itself only 'ix' option
##if exec_target == profile:
##options = 'i'
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
# Don't allow hats to cx?
options . replace ( ' c ' , ' ' )
# Add deny to options
options + = ' d '
# Define the default option
default = None
if ' p ' in options and os . path . exists ( get_profile_filename ( exec_target ) ) :
default = ' CMD_px '
2014-02-10 22:20:36 -08:00
sys . stdout . write ( _ ( ' Target profile exists: %s \n ' ) % get_profile_filename ( exec_target ) )
2013-07-23 04:35:51 +05:30
elif ' i ' in options :
default = ' CMD_ix '
elif ' c ' in options :
default = ' CMD_cx '
elif ' n ' in options :
default = ' CMD_nx '
else :
default = ' DENY '
2013-09-22 22:51:30 +05:30
#
2013-07-23 04:35:51 +05:30
parent_uses_ld_xxx = check_for_LD_XXX ( profile )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
sev_db . unload_variables ( )
2014-05-29 16:53:02 +02:00
sev_db . load_variables ( get_profile_filename ( profile ) )
2013-07-23 04:35:51 +05:30
severity = sev_db . rank ( exec_target , ' x ' )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
# Prompt portion starts
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
q . headers + = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ]
2013-07-23 04:35:51 +05:30
if prog and prog != ' HINT ' :
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Program ' ) , prog ]
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
# to_name should not exist here since, transitioning is already handeled
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Execute ' ) , exec_target ]
q . headers + = [ _ ( ' Severity ' ) , severity ]
2013-09-22 22:51:30 +05:30
2014-02-13 10:52:00 -08:00
# prompt = '\n%s\n' % context_new # XXX
2013-07-23 04:35:51 +05:30
exec_toggle = False
2014-10-07 18:36:01 +05:30
q . functions + = build_x_functions ( default , options , exec_toggle )
2013-09-22 22:51:30 +05:30
2014-02-01 06:14:05 +05:30
# options = '|'.join(options)
2013-07-23 04:35:51 +05:30
seen_events + = 1
regex_options = re . compile ( ' ^CMD_(ix|px|cx|nx|pix|cix|nix|px_safe|cx_safe|nx_safe|pix_safe|cix_safe|nix_safe|ux|ux_safe|EXEC_TOGGLE|DENY)$ ' )
2013-09-22 22:51:30 +05:30
2013-10-01 01:30:50 +05:30
ans = ' '
while not regex_options . search ( ans ) :
2014-10-07 18:36:01 +05:30
ans = q . promptUser ( ) [ 0 ] . strip ( )
2013-07-23 04:35:51 +05:30
if ans . startswith ( ' CMD_EXEC_IX_ ' ) :
exec_toggle = not exec_toggle
2014-10-07 18:36:01 +05:30
q . functions = [ ]
q . functions + = build_x_functions ( default , options , exec_toggle )
2013-07-23 04:35:51 +05:30
ans = ' '
continue
2014-02-24 20:56:28 +01:00
if ans == ' CMD_FINISHED ' :
save_profiles ( )
return
2013-07-23 04:35:51 +05:30
if ans == ' CMD_nx ' or ans == ' CMD_nix ' :
arg = exec_target
ynans = ' n '
if profile == hat :
2014-02-10 22:17:21 -08:00
ynans = aaui . UI_YesNo ( _ ( ' Are you specifying a transition to a local profile? ' ) , ' n ' )
2013-07-23 04:35:51 +05:30
if ynans == ' y ' :
if ans == ' CMD_nx ' :
ans = ' CMD_cx '
else :
ans = ' CMD_cix '
else :
if ans == ' CMD_nx ' :
ans = ' CMD_px '
else :
ans = ' CMD_pix '
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
to_name = aaui . UI_GetString ( _ ( ' Enter profile name to transition to: ' ) , arg )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
regex_optmode = re . compile ( ' CMD_(px|cx|nx|pix|cix|nix) ' )
if ans == ' CMD_ix ' :
exec_mode = str_to_mode ( ' ix ' )
elif regex_optmode . search ( ans ) :
match = regex_optmode . search ( ans ) . groups ( ) [ 0 ]
2013-07-31 19:56:33 +05:30
exec_mode = str_to_mode ( match )
2013-07-23 04:35:51 +05:30
px_default = ' n '
2013-09-21 01:08:34 +05:30
px_msg = _ ( " Should AppArmor sanitise the environment when \n switching profiles? \n \n Sanitising environment is more secure, \n but some applications depend on the presence \n of LD_PRELOAD or LD_LIBRARY_PATH. " )
2013-07-23 04:35:51 +05:30
if parent_uses_ld_xxx :
2013-09-21 01:08:34 +05:30
px_msg = _ ( " Should AppArmor sanitise the environment when \n switching profiles? \n \n Sanitising environment is more secure, \n but this application appears to be using LD_PRELOAD \n or LD_LIBRARY_PATH and sanitising the environment \n could cause functionality problems. " )
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
ynans = aaui . UI_YesNo ( px_msg , px_default )
2013-07-23 04:35:51 +05:30
if ynans == ' y ' :
# Disable the unsafe mode
2014-02-10 22:17:21 -08:00
exec_mode = exec_mode - ( apparmor . aamode . AA_EXEC_UNSAFE | AA_OTHER ( apparmor . aamode . AA_EXEC_UNSAFE ) )
2013-07-23 04:35:51 +05:30
elif ans == ' CMD_ux ' :
exec_mode = str_to_mode ( ' ux ' )
2014-02-10 22:17:21 -08:00
ynans = aaui . UI_YesNo ( _ ( " Launching processes in an unconfined state is a very \n dangerous operation and can cause serious security holes. \n \n Are you absolutely certain you wish to remove all \n AppArmor protection when executing %s ? " ) % exec_target , ' n ' )
2013-07-23 04:35:51 +05:30
if ynans == ' y ' :
2014-02-10 22:17:21 -08:00
ynans = aaui . UI_YesNo ( _ ( " Should AppArmor sanitise the environment when \n running this program unconfined? \n \n Not sanitising the environment when unconfining \n a program opens up significant security holes \n and should be avoided if at all possible. " ) , ' y ' )
2013-07-24 22:12:34 +05:30
if ynans == ' y ' :
2013-07-23 04:35:51 +05:30
# Disable the unsafe mode
2014-02-10 22:17:21 -08:00
exec_mode = exec_mode - ( apparmor . aamode . AA_EXEC_UNSAFE | AA_OTHER ( apparmor . aamode . AA_EXEC_UNSAFE ) )
2013-07-23 04:35:51 +05:30
else :
ans = ' INVALID '
2013-10-01 01:30:50 +05:30
transitions [ context_new ] = ans
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
regex_options = re . compile ( ' CMD_(ix|px|cx|nx|pix|cix|nix) ' )
if regex_options . search ( ans ) :
# For inherit we need r
if exec_mode & str_to_mode ( ' i ' ) :
exec_mode | = str_to_mode ( ' r ' )
else :
if ans == ' CMD_DENY ' :
aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ exec_target ] [ ' mode ' ] = aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ exec_target ] . get ( ' mode ' , str_to_mode ( ' x ' ) ) | str_to_mode ( ' x ' )
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ exec_target ] [ ' audit ' ] = aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ exec_target ] . get ( ' audit ' , set ( ) )
2013-07-23 04:35:51 +05:30
changed [ profile ] = True
# Skip remaining events if they ask to deny exec
if domainchange == ' change ' :
return None
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if ans != ' CMD_DENY ' :
prelog [ ' PERMITTING ' ] [ profile ] [ hat ] [ ' path ' ] [ exec_target ] = prelog [ ' PERMITTING ' ] [ profile ] [ hat ] [ ' path ' ] . get ( exec_target , exec_mode ) | exec_mode
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
log_dict [ ' PERMITTING ' ] [ profile ] = hasher ( )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ exec_target ] [ ' mode ' ] = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ exec_target ] . get ( ' mode ' , exec_mode )
2013-09-22 22:51:30 +05:30
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ exec_target ] [ ' audit ' ] = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ exec_target ] . get ( ' audit ' , set ( ) )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if to_name :
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ exec_target ] [ ' to ' ] = to_name
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if exec_mode & str_to_mode ( ' i ' ) :
2013-07-31 19:56:33 +05:30
#if 'perl' in exec_target:
# aa[profile][hat]['include']['abstractions/perl'] = True
#elif '/bin/bash' in exec_target or '/bin/sh' in exec_target:
# aa[profile][hat]['include']['abstractions/bash'] = True
2013-07-23 04:35:51 +05:30
hashbang = head ( exec_target )
if hashbang . startswith ( ' #! ' ) :
interpreter = hashbang [ 2 : ] . strip ( )
2013-07-27 15:28:12 +05:30
interpreter_path = get_full_path ( interpreter )
2013-07-27 15:32:12 +05:30
interpreter = re . sub ( ' ^(/usr)?/bin/ ' , ' ' , interpreter_path )
2013-09-22 22:51:30 +05:30
2014-11-27 00:42:06 +01:00
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] [ ' mode ' ] = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] . get ( ' mode ' , str_to_mode ( ' ix ' ) ) | str_to_mode ( ' ix ' )
2013-09-22 22:51:30 +05:30
2014-11-27 00:42:06 +01:00
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] [ ' audit ' ] = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ interpreter_path ] . get ( ' audit ' , set ( ) )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if interpreter == ' perl ' :
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' include ' ] [ ' abstractions/perl ' ] = True
2013-07-27 15:28:12 +05:30
elif interpreter in [ ' bash ' , ' dash ' , ' sh ' ] :
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' include ' ] [ ' abstractions/bash ' ] = True
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
# Update tracking info based on kind of change
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if ans == ' CMD_ix ' :
if hat :
2014-02-10 22:20:36 -08:00
profile_changes [ pid ] = ' %s // %s ' % ( profile , hat )
2013-07-23 04:35:51 +05:30
else :
profile_changes [ pid ] = ' %s // ' % profile
elif re . search ( ' ^CMD_(px|nx|pix|nix) ' , ans ) :
if to_name :
exec_target = to_name
if aamode == ' PERMITTING ' :
if domainchange == ' change ' :
profile = exec_target
hat = exec_target
profile_changes [ pid ] = ' %s ' % profile
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
# Check profile exists for px
if not os . path . exists ( get_profile_filename ( exec_target ) ) :
ynans = ' y '
if exec_mode & str_to_mode ( ' i ' ) :
2014-02-10 22:20:36 -08:00
ynans = aaui . UI_YesNo ( _ ( ' A profile for %s does not exist. \n Do you want to create one? ' ) % exec_target , ' n ' )
2013-07-23 04:35:51 +05:30
if ynans == ' y ' :
helpers [ exec_target ] = ' enforce '
if to_name :
2013-07-31 19:56:33 +05:30
autodep ( ' ' , exec_target )
2013-07-23 04:35:51 +05:30
else :
2013-07-31 19:56:33 +05:30
autodep ( exec_target , ' ' )
2013-07-23 04:35:51 +05:30
reload_base ( exec_target )
elif ans . startswith ( ' CMD_cx ' ) or ans . startswith ( ' CMD_cix ' ) :
if to_name :
exec_target = to_name
if aamode == ' PERMITTING ' :
if domainchange == ' change ' :
profile_changes [ pid ] = ' %s // %s ' % ( profile , exec_target )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if not aa [ profile ] . get ( exec_target , False ) :
ynans = ' y '
if exec_mode & str_to_mode ( ' i ' ) :
2014-02-10 22:17:21 -08:00
ynans = aaui . UI_YesNo ( _ ( ' A profile for %s does not exist. \n Do you want to create one? ' ) % exec_target , ' n ' )
2013-07-23 04:35:51 +05:30
if ynans == ' y ' :
hat = exec_target
aa [ profile ] [ hat ] [ ' declared ' ] = False
aa [ profile ] [ hat ] [ ' profile ' ] = True
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if profile != hat :
aa [ profile ] [ hat ] [ ' flags ' ] = aa [ profile ] [ profile ] [ ' flags ' ]
2013-09-22 22:51:30 +05:30
fix save_profile() by fixing some other code
When creating a child profile while using genprof, I get a backtrace:
Traceback (most recent call last):
File "aa-genprof", line 160, in <module>
lp_ret = apparmor.do_logprof_pass(logmark, passno)
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2291, in do_logprof_pass
save_profiles()
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2309, in save_profiles
for prof_name in changed.keys():
RuntimeError: dictionary changed size during iteration
(See https://bugs.launchpad.net/apparmor/+bug/1014304 for more details.)
After digging into the code, it seems for some reason the child profile
is added to "changed" - I doubt this is correct (guess why it's removed
later... ;-)
After digging a bit more, I found out that create_new_profile() is
(ab)used to create a new stub profile to be used as child profile.
create_new_profile then adds the new child (which looks like a normal
profile to it) to "changed".
This patch most probably makes the cleanup round in save_profile()
superfluous by adding a is_stub parameter to create_new_profile(). If
this parameter is set, the new (child) profile is not added to "created"
and "changed".
I intentionally added the two print() lines in safe_profile because
a) I think they will never be displayed
b) I want to know if a) is wrong ;-)
c) it's always nice to have a "nice" error message before displaying
a backtrace ;-)
Acked-by: Steve Beattie <steve@nxnw.org>
2014-06-10 00:44:59 +02:00
stub_profile = create_new_profile ( hat , True )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' flags ' ] = ' complain '
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] = hasher ( )
if stub_profile [ hat ] [ hat ] [ ' allow ' ] . get ( ' path ' , False ) :
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] = stub_profile [ hat ] [ hat ] [ ' allow ' ] [ ' path ' ]
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' include ' ] = hasher ( )
if stub_profile [ hat ] [ hat ] . get ( ' include ' , False ) :
aa [ profile ] [ hat ] [ ' include ' ] = stub_profile [ hat ] [ hat ] [ ' include ' ]
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' netdomain ' ] = hasher ( )
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
file_name = aa [ profile ] [ profile ] [ ' filename ' ]
filelist [ file_name ] [ ' profiles ' ] [ profile ] [ hat ] = True
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
elif ans . startswith ( ' CMD_ux ' ) :
profile_changes [ pid ] = ' unconfined '
if domainchange == ' change ' :
return None
2013-09-22 22:51:30 +05:30
2013-08-11 15:22:07 +05:30
elif typ == ' netdomain ' :
2013-08-21 11:26:09 +05:30
# If netdomain we (should) have pid, profile, hat, program, mode, network family, socket type and protocol
2013-07-23 04:35:51 +05:30
pid , p , h , prog , aamode , family , sock_type , protocol = entry [ : 8 ]
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
if not regex_nullcomplain . search ( p ) and not regex_nullcomplain . search ( h ) :
profile = p
hat = h
if not hat or not profile :
continue
if family and sock_type :
prelog [ aamode ] [ profile ] [ hat ] [ ' netdomain ' ] [ family ] [ sock_type ] = True
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
return None
2013-07-28 08:23:46 +05:30
PROFILE_MODE_RE = re . compile ( ' r|w|l|m|k|a|ix|ux|px|cx|pix|cix|Ux|Px|PUx|Cx|Pix|Cix ' )
PROFILE_MODE_NT_RE = re . compile ( ' r|w|l|m|k|a|x|ix|ux|px|cx|pix|cix|Ux|Px|PUx|Cx|Pix|Cix ' )
PROFILE_MODE_DENY_RE = re . compile ( ' r|w|l|m|k|a|x ' )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
##### Repo related functions
2013-07-24 22:12:34 +05:30
def UI_SelectUpdatedRepoProfile ( profile , p ) :
# To-Do
return False
def UI_repo_signup ( ) :
# To-Do
return None , None
def UI_ask_to_enable_repo ( ) :
# To-Do
pass
def UI_ask_to_upload_profiles ( ) :
# To-Do
pass
def UI_ask_mode_toggles ( audit_toggle , owner_toggle , oldmode ) :
# To-Do
2013-09-21 18:50:00 +05:30
return ( audit_toggle , owner_toggle )
2013-07-24 22:12:34 +05:30
def parse_repo_profile ( fqdbin , repo_url , profile ) :
# To-Do
pass
def set_repo_info ( profile_data , repo_url , username , iden ) :
# To-Do
pass
def is_repo_profile ( profile_data ) :
# To-Do
pass
def get_repo_user_pass ( ) :
# To-Do
pass
2013-07-31 19:56:33 +05:30
def get_preferred_user ( repo_url ) :
# To-Do
pass
def repo_is_enabled ( ) :
# To-Do
return False
2013-07-24 22:12:34 +05:30
def update_repo_profile ( profile ) :
# To-Do
2013-07-27 15:28:12 +05:30
return None
def order_globs ( globs , path ) :
""" Returns the globs in sorted order, more specific behind """
# To-Do
# ATM its lexicographic, should be done to allow better matches later
return sorted ( globs )
2013-07-28 08:23:46 +05:30
def ask_the_questions ( ) :
2013-08-11 15:22:07 +05:30
found = 0
global seen_events
2013-07-27 15:28:12 +05:30
for aamode in sorted ( log_dict . keys ( ) ) :
# Describe the type of changes
if aamode == ' PERMITTING ' :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Complain-mode changes: ' ) )
2013-07-27 15:28:12 +05:30
elif aamode == ' REJECTING ' :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Enforce-mode changes: ' ) )
2013-07-27 15:28:12 +05:30
else :
2013-09-23 21:00:36 +05:30
# This is so wrong!
2013-08-07 14:43:17 +05:30
fatal_error ( _ ( ' Invalid mode found: %s ' ) % aamode )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
for profile in sorted ( log_dict [ aamode ] . keys ( ) ) :
# Update the repo profiles
p = update_repo_profile ( aa [ profile ] [ profile ] )
if p :
UI_SelectUpdatedRepoProfile ( profile , p )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
found + = 1
# Sorted list of hats with the profile name coming first
2013-08-13 00:43:20 +05:30
hats = list ( filter ( lambda key : key != profile , sorted ( log_dict [ aamode ] [ profile ] . keys ( ) ) ) )
2013-07-27 15:28:12 +05:30
if log_dict [ aamode ] [ profile ] . get ( profile , False ) :
hats = [ profile ] + hats
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
for hat in hats :
for capability in sorted ( log_dict [ aamode ] [ profile ] [ hat ] [ ' capability ' ] . keys ( ) ) :
# skip if capability already in profile
if profile_known_capability ( aa [ profile ] [ hat ] , capability ) :
continue
# Load variables? Don't think so.
severity = sev_db . rank ( ' CAP_ %s ' % capability )
default_option = 1
options = [ ]
newincludes = match_cap_includes ( aa [ profile ] [ hat ] , capability )
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if newincludes :
2014-02-10 22:20:36 -08:00
options + = list ( map ( lambda inc : ' #include < %s > ' % inc , sorted ( set ( newincludes ) ) ) )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if options :
options . append ( ' capability %s ' % capability )
2014-10-07 18:36:01 +05:30
q . options = options
q . selected = default_option - 1
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . headers = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ]
q . headers + = [ _ ( ' Capability ' ) , capability ]
q . headers + = [ _ ( ' Severity ' ) , severity ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
audit_toggle = 0
2014-11-15 01:38:29 +01:00
audit = ' '
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . functions = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_AUDIT_NEW ' ,
2013-09-19 10:32:19 +05:30
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
# In complain mode: events default to allow
# In enforce mode: events default to deny
2014-10-07 18:36:01 +05:30
q . default = ' CMD_DENY '
2013-07-27 15:28:12 +05:30
if aamode == ' PERMITTING ' :
2014-10-07 18:36:01 +05:30
q . default = ' CMD_ALLOW '
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
seen_events + = 1
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
done = False
while not done :
2014-10-07 18:36:01 +05:30
ans , selected = q . promptUser ( )
2014-02-24 20:56:28 +01:00
if ans == ' CMD_FINISHED ' :
save_profiles ( )
return
2013-07-28 08:23:46 +05:30
# Ignore the log entry
if ans == ' CMD_IGNORE_ENTRY ' :
done = True
break
2013-09-22 22:51:30 +05:30
2014-11-15 01:38:29 +01:00
if ans . startswith ( ' CMD_AUDIT ' ) :
2013-07-27 15:28:12 +05:30
audit_toggle = not audit_toggle
if audit_toggle :
2014-11-15 01:38:29 +01:00
audit = ' audit '
audit_cmd = ' CMD_AUDIT_OFF '
2013-07-27 15:28:12 +05:30
else :
2014-11-15 01:38:29 +01:00
audit = ' '
audit_cmd = ' CMD_AUDIT_NEW '
q . functions = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , audit_cmd ,
' CMD_ABORT ' , ' CMD_FINISHED ' , ]
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . headers = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ,
2013-08-07 14:43:17 +05:30
_ ( ' Capability ' ) , audit + capability ,
_ ( ' Severity ' ) , severity ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if ans == ' CMD_ALLOW ' :
2013-08-17 12:34:42 +05:30
selection = ' '
if options :
selection = options [ selected ]
2013-09-22 22:51:30 +05:30
match = re_match_include ( selection )
2013-07-27 15:28:12 +05:30
if match :
deleted = False
2014-02-10 22:20:36 -08:00
inc = match # .groups()[0]
2013-07-27 15:28:12 +05:30
deleted = delete_duplicates ( aa [ profile ] [ hat ] , inc )
aa [ profile ] [ hat ] [ ' include ' ] [ inc ] = True
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Adding %s to profile. ' ) % selection )
2013-07-27 15:28:12 +05:30
if deleted :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Deleted %s previous matching profile entries. ' ) % deleted )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' capability ' ] [ capability ] [ ' set ' ] = True
aa [ profile ] [ hat ] [ ' allow ' ] [ ' capability ' ] [ capability ] [ ' audit ' ] = audit_toggle
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Adding capability %s to profile. ' ) % capability )
2013-07-27 15:28:12 +05:30
done = True
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_DENY ' :
aa [ profile ] [ hat ] [ ' deny ' ] [ ' capability ' ] [ capability ] [ ' set ' ] = True
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Denying capability %s to profile. ' ) % capability )
2013-07-27 15:28:12 +05:30
done = True
else :
done = False
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
# Process all the path entries.
for path in sorted ( log_dict [ aamode ] [ profile ] [ hat ] [ ' path ' ] . keys ( ) ) :
mode = log_dict [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ]
# Lookup modes from profile
2013-08-11 18:30:01 +05:30
allow_mode = set ( )
allow_audit = set ( )
deny_mode = set ( )
deny_audit = set ( )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
fmode , famode , fm = rematchfrag ( aa [ profile ] [ hat ] , ' allow ' , path )
2013-07-27 15:28:12 +05:30
if fmode :
allow_mode | = fmode
if famode :
allow_audit | = famode
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
cm , cam , m = rematchfrag ( aa [ profile ] [ hat ] , ' deny ' , path )
2013-07-27 15:28:12 +05:30
if cm :
deny_mode | = cm
if cam :
deny_audit | = cam
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
imode , iamode , im = match_prof_incs_to_path ( aa [ profile ] [ hat ] , ' allow ' , path )
if imode :
allow_mode | = imode
if iamode :
allow_audit | = iamode
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
cm , cam , m = match_prof_incs_to_path ( aa [ profile ] [ hat ] , ' deny ' , path )
if cm :
deny_mode | = cm
if cam :
deny_audit | = cam
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
if deny_mode & apparmor . aamode . AA_MAY_EXEC :
2013-08-11 23:16:05 +05:30
deny_mode | = apparmor . aamode . ALL_AA_EXEC_TYPE
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
# Mask off the denied modes
2013-08-11 18:30:01 +05:30
mode = mode - deny_mode
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
# 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
2014-02-10 22:17:21 -08:00
if mode & apparmor . aamode . AA_MAY_EXEC :
2013-07-27 15:28:12 +05:30
# Remove all type access permission
2013-08-11 23:16:05 +05:30
mode = mode - apparmor . aamode . ALL_AA_EXEC_TYPE
2014-02-10 22:17:21 -08:00
if not allow_mode & apparmor . aamode . AA_MAY_EXEC :
2013-07-27 15:28:12 +05:30
mode | = str_to_mode ( ' ix ' )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
# m is not implied by ix
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
### 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'):
2013-08-11 18:30:01 +05:30
## mode = mode - AA_EXEC_MMAP
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if not mode :
continue
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
matches = [ ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if fmode :
2013-10-01 01:30:50 +05:30
matches + = fm
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if imode :
2013-10-01 01:30:50 +05:30
matches + = im
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if not mode_contains ( allow_mode , mode ) :
default_option = 1
options = [ ]
newincludes = [ ]
include_valid = False
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
for incname in include . keys ( ) :
include_valid = False
# If already present skip
2014-11-26 20:25:07 +01:00
if aa [ profile ] [ hat ] [ ' include ' ] . get ( incname , False ) :
2013-07-27 15:28:12 +05:30
continue
2013-08-11 15:22:07 +05:30
if incname . startswith ( profile_dir ) :
2014-02-10 22:20:36 -08:00
incname = incname . replace ( profile_dir + ' / ' , ' ' , 1 )
2013-09-22 22:51:30 +05:30
2013-08-11 15:22:07 +05:30
include_valid = valid_include ( ' ' , incname )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if not include_valid :
continue
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
cm , am , m = match_include_to_path ( incname , ' allow ' , path )
2013-08-11 23:16:05 +05:30
2013-07-27 15:28:12 +05:30
if cm and mode_contains ( cm , mode ) :
2013-08-11 23:16:05 +05:30
dm = match_include_to_path ( incname , ' deny ' , path ) [ 0 ]
2013-07-27 15:28:12 +05:30
# If the mode is denied
if not mode & dm :
2013-08-13 00:43:20 +05:30
if not list ( filter ( lambda s : ' /** ' == s , m ) ) :
2013-07-27 15:28:12 +05:30
newincludes . append ( incname )
# Add new includes to the options
if newincludes :
2013-08-17 12:34:42 +05:30
options + = list ( map ( lambda s : ' #include < %s > ' % s , sorted ( set ( newincludes ) ) ) )
2013-07-27 15:28:12 +05:30
# We should have literal the path in options list too
options . append ( path )
# Add any the globs matching path from logprof
2013-07-28 08:23:46 +05:30
globs = glob_common ( path )
2013-07-27 15:28:12 +05:30
if globs :
matches + = globs
# Add any user entered matching globs
for user_glob in user_globs :
if matchliteral ( user_glob , path ) :
matches . append ( user_glob )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
matches = list ( set ( matches ) )
if path in matches :
matches . remove ( path )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
options + = order_globs ( matches , path )
default_option = len ( options )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
sev_db . unload_variables ( )
2013-08-13 00:43:20 +05:30
sev_db . load_variables ( get_profile_filename ( profile ) )
2013-07-27 15:28:12 +05:30
severity = sev_db . rank ( path , mode_to_str ( mode ) )
sev_db . unload_variables ( )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
audit_toggle = 0
2013-08-05 18:55:34 +05:30
owner_toggle = 0
if cfg [ ' settings ' ] [ ' default_owner_prompt ' ] :
owner_toggle = cfg [ ' settings ' ] [ ' default_owner_prompt ' ]
2013-07-27 15:28:12 +05:30
done = False
while not done :
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
q . headers = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ,
2013-08-07 14:43:17 +05:30
_ ( ' Path ' ) , path ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if allow_mode :
mode | = allow_mode
tail = ' '
s = ' '
prompt_mode = None
if owner_toggle == 0 :
prompt_mode = flatten_mode ( mode )
2013-08-07 14:43:17 +05:30
tail = ' ' + _ ( ' (owner permissions off) ' )
2013-07-27 15:28:12 +05:30
elif owner_toggle == 1 :
prompt_mode = mode
elif owner_toggle == 2 :
2013-08-11 18:30:01 +05:30
prompt_mode = allow_mode | owner_flatten_mode ( mode - allow_mode )
2013-08-07 14:43:17 +05:30
tail = ' ' + _ ( ' (force new perms to owner) ' )
2013-07-27 15:28:12 +05:30
else :
prompt_mode = owner_flatten_mode ( mode )
2013-08-07 14:43:17 +05:30
tail = ' ' + _ ( ' (force all rule perms to owner) ' )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if audit_toggle == 1 :
s = mode_to_str_user ( allow_mode )
if allow_mode :
s + = ' , '
2013-08-11 18:30:01 +05:30
s + = ' audit ' + mode_to_str_user ( prompt_mode - allow_mode ) + tail
2013-07-27 15:28:12 +05:30
elif audit_toggle == 2 :
s = ' audit ' + mode_to_str_user ( prompt_mode ) + tail
else :
s = mode_to_str_user ( prompt_mode ) + tail
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Old Mode ' ) , mode_to_str_user ( allow_mode ) ,
2013-08-07 14:43:17 +05:30
_ ( ' New Mode ' ) , s ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
else :
s = ' '
tail = ' '
prompt_mode = None
if audit_toggle :
s = ' audit '
if owner_toggle == 0 :
prompt_mode = flatten_mode ( mode )
2013-08-07 14:43:17 +05:30
tail = ' ' + _ ( ' (owner permissions off) ' )
2013-07-27 15:28:12 +05:30
elif owner_toggle == 1 :
prompt_mode = mode
else :
prompt_mode = owner_flatten_mode ( mode )
2013-08-07 14:43:17 +05:30
tail = ' ' + _ ( ' (force perms to owner) ' )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
s = mode_to_str_user ( prompt_mode )
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Mode ' ) , s ]
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . headers + = [ _ ( ' Severity ' ) , severity ]
q . options = options
q . selected = default_option - 1
q . functions = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_GLOB ' ,
2013-08-11 15:22:07 +05:30
' CMD_GLOBEXT ' , ' CMD_NEW ' , ' CMD_ABORT ' ,
2013-09-19 10:32:19 +05:30
' CMD_FINISHED ' , ' CMD_OTHER ' ]
2014-10-07 18:36:01 +05:30
q . default = ' CMD_DENY '
2013-07-27 15:28:12 +05:30
if aamode == ' PERMITTING ' :
2014-10-07 18:36:01 +05:30
q . default = ' CMD_ALLOW '
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
seen_events + = 1
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
ans , selected = q . promptUser ( )
2013-09-22 22:51:30 +05:30
2014-02-24 20:56:28 +01:00
if ans == ' CMD_FINISHED ' :
save_profiles ( )
return
2013-07-28 08:23:46 +05:30
if ans == ' CMD_IGNORE_ENTRY ' :
done = True
break
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if ans == ' CMD_OTHER ' :
audit_toggle , owner_toggle = UI_ask_mode_toggles ( audit_toggle , owner_toggle , allow_mode )
elif ans == ' CMD_USER_TOGGLE ' :
owner_toggle + = 1
if not allow_mode and owner_toggle == 2 :
owner_toggle + = 1
if owner_toggle > 3 :
owner_toggle = 0
elif ans == ' CMD_ALLOW ' :
path = options [ selected ]
done = True
2014-02-10 22:20:36 -08:00
match = re_match_include ( path ) # .search('^#include\s+<(.+)>$', path)
2013-07-27 15:28:12 +05:30
if match :
2014-02-10 22:20:36 -08:00
inc = match # .groups()[0]
2013-07-27 15:28:12 +05:30
deleted = 0
deleted = delete_duplicates ( aa [ profile ] [ hat ] , inc )
2014-02-10 22:20:36 -08:00
aa [ profile ] [ hat ] [ ' include ' ] [ inc ] = True
changed [ profile ] = True
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Adding %s to profile. ' ) % path )
2013-07-27 15:28:12 +05:30
if deleted :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Deleted %s previous matching profile entries. ' ) % deleted )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
else :
2014-11-26 20:25:07 +01:00
if path in aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] :
if aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] . get ( ' mode ' , False ) :
mode | = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] [ ' mode ' ]
2013-08-21 11:26:09 +05:30
deleted = [ ]
2013-07-27 15:28:12 +05:30
for entry in aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] . keys ( ) :
if path == entry :
continue
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if matchregexp ( path , entry ) :
if mode_contains ( mode , aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ entry ] [ ' mode ' ] ) :
2013-08-21 11:26:09 +05:30
deleted . append ( entry )
for entry in deleted :
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] . pop ( entry )
deleted = len ( deleted )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if owner_toggle == 0 :
mode = flatten_mode ( mode )
#elif owner_toggle == 1:
# mode = mode
elif owner_toggle == 2 :
2013-08-11 18:30:01 +05:30
mode = allow_mode | owner_flatten_mode ( mode - allow_mode )
2013-07-27 15:28:12 +05:30
elif owner_toggle == 3 :
mode = owner_flatten_mode ( mode )
2013-09-22 22:51:30 +05:30
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] [ ' mode ' ] = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] . get ( ' mode ' , set ( ) ) | mode
2013-09-22 22:51:30 +05:30
2013-08-11 23:16:05 +05:30
tmpmode = set ( )
2013-07-27 15:28:12 +05:30
if audit_toggle == 1 :
2014-02-10 22:20:36 -08:00
tmpmode = mode - allow_mode
2013-07-27 15:28:12 +05:30
elif audit_toggle == 2 :
2013-09-22 22:51:30 +05:30
tmpmode = mode
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] [ ' audit ' ] = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] . get ( ' audit ' , set ( ) ) | tmpmode
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2014-09-14 23:47:00 +05:30
aaui . UI_Info ( _ ( ' Adding %(path)s %(mode)s to profile ' ) % { ' path ' : path , ' mode ' : mode_to_str_user ( mode ) } )
2013-07-27 15:28:12 +05:30
if deleted :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Deleted %s previous matching profile entries. ' ) % deleted )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_DENY ' :
2013-08-26 00:23:59 +05:30
path = options [ selected ] . strip ( )
2013-07-27 15:28:12 +05:30
# Add new entry?
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ path ] [ ' mode ' ] = aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ path ] . get ( ' mode ' , set ( ) ) | ( mode - allow_mode )
2013-09-22 22:51:30 +05:30
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ path ] [ ' audit ' ] = aa [ profile ] [ hat ] [ ' deny ' ] [ ' path ' ] [ path ] . get ( ' audit ' , set ( ) )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
done = True
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_NEW ' :
arg = options [ selected ]
2013-07-28 08:23:46 +05:30
if not re_match_include ( arg ) :
2014-02-10 22:17:21 -08:00
ans = aaui . UI_GetString ( _ ( ' Enter new path: ' ) , arg )
2013-07-27 15:28:12 +05:30
if ans :
if not matchliteral ( ans , path ) :
2014-09-14 23:47:00 +05:30
ynprompt = _ ( ' The specified path does not match this log entry: \n \n Log Entry: %(path)s \n Entered Path: %(ans)s \n Do you really want to use this path? ' ) % { ' path ' : path , ' ans ' : ans }
2014-02-10 22:17:21 -08:00
key = aaui . UI_YesNo ( ynprompt , ' n ' )
2013-07-27 15:28:12 +05:30
if key == ' n ' :
continue
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
user_globs . append ( ans )
2014-08-25 22:49:29 +02:00
options , default_option = add_to_options ( options , ans )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_GLOB ' :
newpath = options [ selected ] . strip ( )
2013-07-28 08:23:46 +05:30
if not re_match_include ( newpath ) :
2013-08-30 03:54:31 +05:30
newpath = glob_path ( newpath )
2014-08-25 22:49:29 +02:00
options , default_option = add_to_options ( options , newpath )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_GLOBEXT ' :
newpath = options [ selected ] . strip ( )
2013-07-28 08:23:46 +05:30
if not re_match_include ( newpath ) :
2013-08-30 03:54:31 +05:30
newpath = glob_path_withext ( newpath )
2014-08-25 22:49:29 +02:00
options , default_option = add_to_options ( options , newpath )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif re . search ( ' \ d ' , ans ) :
default_option = ans
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
#
for family in sorted ( log_dict [ aamode ] [ profile ] [ hat ] [ ' netdomain ' ] . keys ( ) ) :
# severity handling for net toggles goes here
2014-10-14 12:54:39 +02:00
for sock_type in sorted ( log_dict [ aamode ] [ profile ] [ hat ] [ ' netdomain ' ] [ family ] . keys ( ) ) :
2013-07-27 15:28:12 +05:30
if profile_known_network ( aa [ profile ] [ hat ] , family , sock_type ) :
continue
default_option = 1
options = [ ]
2013-07-28 08:23:46 +05:30
newincludes = match_net_includes ( aa [ profile ] [ hat ] , family , sock_type )
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
2013-07-27 15:28:12 +05:30
if newincludes :
2014-02-10 22:20:36 -08:00
options + = list ( map ( lambda s : ' #include < %s > ' % s , sorted ( set ( newincludes ) ) ) )
2013-07-27 15:28:12 +05:30
if options :
options . append ( ' network %s %s ' % ( family , sock_type ) )
2014-10-07 18:36:01 +05:30
q . options = options
q . selected = default_option - 1
2013-09-22 22:51:30 +05:30
2014-10-07 18:36:01 +05:30
q . headers = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ]
q . headers + = [ _ ( ' Network Family ' ) , family ]
q . headers + = [ _ ( ' Socket Type ' ) , sock_type ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
audit_toggle = 0
2014-10-07 18:36:01 +05:30
q . functions = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_AUDIT_NEW ' ,
2013-09-19 10:32:19 +05:30
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2014-10-07 18:36:01 +05:30
q . default = ' CMD_DENY '
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if aamode == ' PERMITTING ' :
2014-10-07 18:36:01 +05:30
q . default = ' CMD_ALLOW '
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
seen_events + = 1
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
done = False
while not done :
2014-10-07 18:36:01 +05:30
ans , selected = q . promptUser ( )
2014-02-24 20:56:28 +01:00
if ans == ' CMD_FINISHED ' :
save_profiles ( )
return
2013-07-28 08:23:46 +05:30
if ans == ' CMD_IGNORE_ENTRY ' :
done = True
break
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if ans . startswith ( ' CMD_AUDIT ' ) :
audit_toggle = not audit_toggle
audit = ' '
if audit_toggle :
audit = ' audit '
2014-10-07 18:36:01 +05:30
q . functions = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_AUDIT_OFF ' ,
2013-07-27 15:28:12 +05:30
' CMD_ABORT ' , ' CMD_FINISHED ' ]
else :
2014-10-07 18:36:01 +05:30
q . functions = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_AUDIT_NEW ' ,
2013-07-27 15:28:12 +05:30
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2014-10-07 18:36:01 +05:30
q . headers = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ]
q . headers + = [ _ ( ' Network Family ' ) , audit + family ]
q . headers + = [ _ ( ' Socket Type ' ) , sock_type ]
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_ALLOW ' :
2014-10-14 21:28:32 +02:00
if options :
selection = options [ selected ]
else :
selection = ' network %s %s ' % ( family , sock_type )
2013-07-27 15:28:12 +05:30
done = True
2014-02-10 22:20:36 -08:00
if re_match_include ( selection ) : # re.search('#include\s+<.+>$', selection):
inc = re_match_include ( selection ) # re.search('#include\s+<(.+)>$', selection).groups()[0]
deleted = 0
2013-07-27 15:28:12 +05:30
deleted = delete_duplicates ( aa [ profile ] [ hat ] , inc )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
aa [ profile ] [ hat ] [ ' include ' ] [ inc ] = True
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Adding %s to profile ' ) % selection )
2013-07-27 15:28:12 +05:30
if deleted :
2014-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Deleted %s previous matching profile entries. ' ) % deleted )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
else :
aa [ profile ] [ hat ] [ ' allow ' ] [ ' netdomain ' ] [ ' audit ' ] [ family ] [ sock_type ] = audit_toggle
aa [ profile ] [ hat ] [ ' allow ' ] [ ' netdomain ' ] [ ' rule ' ] [ family ] [ sock_type ] = True
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
changed [ profile ] = True
2013-09-22 22:51:30 +05:30
2014-09-14 23:47:00 +05:30
aaui . UI_Info ( _ ( ' Adding network access %(family)s %(type)s to profile. ' ) % { ' family ' : family , ' type ' : sock_type } )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
elif ans == ' CMD_DENY ' :
done = True
aa [ profile ] [ hat ] [ ' deny ' ] [ ' netdomain ' ] [ ' rule ' ] [ family ] [ sock_type ] = True
changed [ profile ] = True
2014-09-14 23:47:00 +05:30
aaui . UI_Info ( _ ( ' Denying network access %(family)s %(type)s to profile ' ) % { ' family ' : family , ' type ' : sock_type } )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
else :
done = False
2013-07-24 22:12:34 +05:30
2014-08-25 22:49:29 +02:00
def add_to_options ( options , newpath ) :
if newpath not in options :
options . append ( newpath )
default_option = options . index ( newpath ) + 1
return ( options , default_option )
2013-08-30 03:54:31 +05:30
def glob_path ( newpath ) :
""" Glob the given file path """
if newpath [ - 1 ] == ' / ' :
if newpath [ - 4 : ] == ' /**/ ' or newpath [ - 3 : ] == ' /*/ ' :
# /foo/**/ and /foo/*/ => /**/
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' /[^/]+/ \ * { 1,2}/$ ' , ' /**/ ' , newpath ) # re.sub('/[^/]+/\*{1,2}$/', '/\*\*/', newpath)
2013-08-30 03:54:31 +05:30
elif re . search ( ' /[^/]+ \ * \ *[^/]*/$ ' , newpath ) :
# /foo**/ and /foo**bar/ => /**/
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' /[^/]+ \ * \ *[^/]*/$ ' , ' /**/ ' , newpath )
2013-08-30 03:54:31 +05:30
elif re . search ( ' / \ * \ *[^/]+/$ ' , newpath ) :
# /**bar/ => /**/
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' / \ * \ *[^/]+/$ ' , ' /**/ ' , newpath )
2013-08-30 03:54:31 +05:30
else :
newpath = re . sub ( ' /[^/]+/$ ' , ' /*/ ' , newpath )
2013-09-22 22:51:30 +05:30
else :
2013-08-30 03:54:31 +05:30
if newpath [ - 3 : ] == ' /** ' or newpath [ - 2 : ] == ' /* ' :
# /foo/** and /foo/* => /**
2013-09-22 22:51:30 +05:30
newpath = re . sub ( ' /[^/]+/ \ * { 1,2}$ ' , ' /** ' , newpath )
2013-08-30 03:54:31 +05:30
elif re . search ( ' /[^/]* \ * \ *[^/]+$ ' , newpath ) :
# /**foo and /foor**bar => /**
2013-09-22 22:51:30 +05:30
newpath = re . sub ( ' /[^/]* \ * \ *[^/]+$ ' , ' /** ' , newpath )
2013-08-30 03:54:31 +05:30
elif re . search ( ' /[^/]+ \ * \ *$ ' , newpath ) :
# /foo** => /**
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' /[^/]+ \ * \ *$ ' , ' /** ' , newpath )
2013-08-30 03:54:31 +05:30
else :
newpath = re . sub ( ' /[^/]+$ ' , ' /* ' , newpath )
return newpath
def glob_path_withext ( newpath ) :
""" Glob given file path with extension """
# match /**.ext and /*.ext
match = re . search ( ' / \ * { 1,2}( \ .[^/]+)$ ' , newpath )
if match :
# /foo/**.ext and /foo/*.ext => /**.ext
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' /[^/]+/ \ * { 1,2} \ .[^/]+$ ' , ' /** ' + match . groups ( ) [ 0 ] , newpath )
2013-08-30 03:54:31 +05:30
elif re . search ( ' /[^/]+ \ * \ *[^/]* \ .[^/]+$ ' , newpath ) :
# /foo**.ext and /foo**bar.ext => /**.ext
match = re . search ( ' /[^/]+ \ * \ *[^/]*( \ .[^/]+)$ ' , newpath )
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' /[^/]+ \ * \ *[^/]* \ .[^/]+$ ' , ' /** ' + match . groups ( ) [ 0 ] , newpath )
2013-08-30 03:54:31 +05:30
elif re . search ( ' / \ * \ *[^/]+ \ .[^/]+$ ' , newpath ) :
# /**foo.ext => /**.ext
match = re . search ( ' / \ * \ *[^/]+( \ .[^/]+)$ ' , newpath )
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' / \ * \ *[^/]+ \ .[^/]+$ ' , ' /** ' + match . groups ( ) [ 0 ] , newpath )
2013-08-30 03:54:31 +05:30
else :
match = re . search ( ' ( \ .[^/]+)$ ' , newpath )
if match :
2014-02-10 22:20:36 -08:00
newpath = re . sub ( ' /[^/]+( \ .[^/]+)$ ' , ' /* ' + match . groups ( ) [ 0 ] , newpath )
2013-09-22 22:51:30 +05:30
return newpath
2013-08-30 03:54:31 +05:30
2013-07-28 08:23:46 +05:30
def delete_net_duplicates ( netrules , incnetrules ) :
deleted = 0
2013-09-23 03:47:15 +05:30
hasher_obj = hasher ( )
2013-09-23 02:14:11 +05:30
copy_netrules = deepcopy ( netrules )
2013-07-28 08:23:46 +05:30
if incnetrules and netrules :
incnetglob = False
# Delete matching rules from abstractions
if incnetrules . get ( ' all ' , False ) :
incnetglob = True
2013-09-23 02:14:11 +05:30
for fam in copy_netrules [ ' rule ' ] . keys ( ) :
2013-09-23 03:47:15 +05:30
if incnetglob or ( type ( incnetrules [ ' rule ' ] [ fam ] ) != type ( hasher_obj ) and incnetrules [ ' rule ' ] [ fam ] ) :
if type ( netrules [ ' rule ' ] [ fam ] ) == type ( hasher_obj ) :
2013-07-28 08:23:46 +05:30
deleted + = len ( netrules [ ' rule ' ] [ fam ] . keys ( ) )
else :
deleted + = 1
netrules [ ' rule ' ] . pop ( fam )
2013-09-23 03:47:15 +05:30
elif type ( netrules [ ' rule ' ] [ fam ] ) != type ( hasher_obj ) and netrules [ ' rule ' ] [ fam ] :
2013-07-28 08:23:46 +05:30
continue
else :
2013-09-23 21:00:36 +05:30
for socket_type in copy_netrules [ ' rule ' ] [ fam ] . keys ( ) :
2013-09-23 23:05:25 +05:30
if incnetrules [ ' rule ' ] [ fam ] . get ( socket_type , False ) :
2013-09-23 02:14:11 +05:30
netrules [ ' rule ' ] [ fam ] . pop ( socket_type )
2013-07-28 08:23:46 +05:30
deleted + = 1
return deleted
def delete_cap_duplicates ( profilecaps , inccaps ) :
2013-08-21 11:26:09 +05:30
deleted = [ ]
2013-07-28 08:23:46 +05:30
if profilecaps and inccaps :
for capname in profilecaps . keys ( ) :
2014-03-20 14:27:24 -05:00
# XXX The presence of a bare capability rule ("capability,") should
# cause more specific capability rules
# ("capability audit_control,") to be deleted
2013-07-28 08:23:46 +05:30
if inccaps [ capname ] . get ( ' set ' , False ) == 1 :
2013-08-21 11:26:09 +05:30
deleted . append ( capname )
for capname in deleted :
profilecaps . pop ( capname )
2013-09-22 22:51:30 +05:30
2013-08-21 11:26:09 +05:30
return len ( deleted )
2013-07-28 08:23:46 +05:30
def delete_path_duplicates ( profile , incname , allow ) :
2013-08-19 12:37:47 +05:30
deleted = [ ]
2013-07-28 08:23:46 +05:30
for entry in profile [ allow ] [ ' path ' ] . keys ( ) :
2014-02-10 22:20:36 -08:00
if entry == ' #include < %s > ' % incname :
2013-07-28 08:23:46 +05:30
continue
2014-04-23 16:28:17 -05:00
# XXX Make this code smart enough to know that bare file rules
# makes some path rules unnecessary. For example, "/dev/random r,"
# would no longer be needed if "file," was present.
2013-07-28 08:23:46 +05:30
cm , am , m = match_include_to_path ( incname , allow , entry )
if cm and mode_contains ( cm , profile [ allow ] [ ' path ' ] [ entry ] [ ' mode ' ] ) and mode_contains ( am , profile [ allow ] [ ' path ' ] [ entry ] [ ' audit ' ] ) :
2013-08-19 12:37:47 +05:30
deleted . append ( entry )
2013-09-22 22:51:30 +05:30
2013-08-19 12:37:47 +05:30
for entry in deleted :
profile [ allow ] [ ' path ' ] . pop ( entry )
return len ( deleted )
2013-07-28 08:23:46 +05:30
def delete_duplicates ( profile , incname ) :
deleted = 0
# Allow rules covered by denied rules shouldn't be deleted
# only a subset allow rules may actually be denied
2013-09-17 11:46:17 +05:30
if include . get ( incname , False ) :
deleted + = delete_net_duplicates ( profile [ ' allow ' ] [ ' netdomain ' ] , include [ incname ] [ incname ] [ ' allow ' ] [ ' netdomain ' ] )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
deleted + = delete_net_duplicates ( profile [ ' deny ' ] [ ' netdomain ' ] , include [ incname ] [ incname ] [ ' deny ' ] [ ' netdomain ' ] )
2013-09-22 22:51:30 +05:30
2013-09-19 10:32:19 +05:30
deleted + = delete_cap_duplicates ( profile [ ' allow ' ] [ ' capability ' ] , include [ incname ] [ incname ] [ ' allow ' ] [ ' capability ' ] )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
deleted + = delete_cap_duplicates ( profile [ ' deny ' ] [ ' capability ' ] , include [ incname ] [ incname ] [ ' deny ' ] [ ' capability ' ] )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
deleted + = delete_path_duplicates ( profile , incname , ' allow ' )
deleted + = delete_path_duplicates ( profile , incname , ' deny ' )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
elif filelist . get ( incname , False ) :
deleted + = delete_net_duplicates ( profile [ ' allow ' ] [ ' netdomain ' ] , filelist [ incname ] [ incname ] [ ' allow ' ] [ ' netdomain ' ] )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
deleted + = delete_net_duplicates ( profile [ ' deny ' ] [ ' netdomain ' ] , filelist [ incname ] [ incname ] [ ' deny ' ] [ ' netdomain ' ] )
2013-09-22 22:51:30 +05:30
2013-09-19 10:32:19 +05:30
deleted + = delete_cap_duplicates ( profile [ ' allow ' ] [ ' capability ' ] , filelist [ incname ] [ incname ] [ ' allow ' ] [ ' capability ' ] )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
deleted + = delete_cap_duplicates ( profile [ ' deny ' ] [ ' capability ' ] , filelist [ incname ] [ incname ] [ ' deny ' ] [ ' capability ' ] )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
deleted + = delete_path_duplicates ( profile , incname , ' allow ' )
deleted + = delete_path_duplicates ( profile , incname , ' deny ' )
2013-09-22 22:51:30 +05:30
2013-09-17 11:46:17 +05:30
return deleted
2013-07-28 08:23:46 +05:30
def match_net_include ( incname , family , type ) :
2013-09-23 19:32:25 +05:30
includelist = [ incname ]
2013-07-28 08:23:46 +05:30
checked = [ ]
name = None
if includelist :
name = includelist . pop ( 0 )
while name :
checked . append ( name )
if netrules_access_check ( include [ name ] [ name ] [ ' allow ' ] [ ' netdomain ' ] , family , type ) :
return True
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
if include [ name ] [ name ] [ ' include ' ] . keys ( ) and name not in checked :
includelist + = include [ name ] [ name ] [ ' include ' ] . keys ( )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
if len ( includelist ) :
name = includelist . pop ( 0 )
else :
name = False
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return False
2013-07-28 08:23:46 +05:30
def match_cap_includes ( profile , cap ) :
newincludes = [ ]
for incname in include . keys ( ) :
2013-07-30 20:13:08 +05:30
if valid_include ( profile , incname ) and include [ incname ] [ incname ] [ ' allow ' ] [ ' capability ' ] [ cap ] . get ( ' set ' , False ) == 1 :
2013-09-22 22:51:30 +05:30
newincludes . append ( incname )
2013-07-28 08:23:46 +05:30
return newincludes
def re_match_include ( path ) :
""" Matches the path for include and returns the include path """
2013-08-11 23:16:05 +05:30
regex_include = re . compile ( ' ^ \ s*#?include \ s*<(.*)> \ s*(#.*)?$ ' )
2013-07-28 08:23:46 +05:30
match = regex_include . search ( path )
if match :
return match . groups ( ) [ 0 ]
else :
return None
2013-07-30 20:13:08 +05:30
def valid_include ( profile , incname ) :
2013-08-11 15:22:07 +05:30
if profile and profile [ ' include ' ] . get ( incname , False ) :
2013-07-30 20:13:08 +05:30
return False
if cfg [ ' settings ' ] [ ' custom_includes ' ] :
for incm in cfg [ ' settings ' ] [ ' custom_includes ' ] . split ( ) :
if incm == incname :
return True
if incname . startswith ( ' abstractions/ ' ) and os . path . isfile ( profile_dir + ' / ' + incname ) :
return True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return False
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
def match_net_includes ( profile , family , nettype ) :
newincludes = [ ]
for incname in include . keys ( ) :
2013-09-22 22:51:30 +05:30
2014-10-20 20:07:24 +02:00
if valid_include ( profile , incname ) and match_net_include ( incname , family , nettype ) :
2013-07-28 08:23:46 +05:30
newincludes . append ( incname )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
return newincludes
2013-08-21 11:26:09 +05:30
def do_logprof_pass ( logmark = ' ' , passno = 0 , pid = pid ) :
2013-07-28 08:23:46 +05:30
# set up variables for this pass
2014-02-13 10:52:00 -08:00
# t = hasher()
2013-08-11 15:22:07 +05:30
# transitions = hasher()
2014-02-13 10:52:00 -08:00
# seen = hasher() # XXX global?
2013-08-11 15:22:07 +05:30
global log
2013-07-28 08:23:46 +05:30
log = [ ]
2014-03-06 10:34:08 -08:00
global existing_profiles
2013-08-11 15:22:07 +05:30
global sev_db
# aa = hasher()
# profile_changes = hasher()
# prelog = hasher()
# log_dict = hasher()
# changed = dict()
2014-02-13 10:52:00 -08:00
# skip = hasher() # XXX global?
2013-08-11 15:22:07 +05:30
# filelist = hasher()
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
aaui . UI_Info ( _ ( ' Reading log entries from %s . ' ) % filename )
2013-09-22 22:51:30 +05:30
2013-08-21 11:26:09 +05:30
if not passno :
2014-02-10 22:20:36 -08:00
aaui . UI_Info ( _ ( ' Updating AppArmor profiles in %s . ' ) % profile_dir )
2013-08-21 11:26:09 +05:30
read_profiles ( )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
if not sev_db :
2013-08-07 14:43:17 +05:30
sev_db = apparmor . severity . Severity ( CONFDIR + ' /severity.db ' , _ ( ' unknown ' ) )
2013-08-11 15:22:07 +05:30
#print(pid)
#print(existing_profiles)
2013-07-28 08:23:46 +05:30
##if not repo_cf and cfg['repostory']['url']:
## repo_cfg = read_config('repository.conf')
## if not repo_cfg['repository'].get('enabled', False) or repo_cfg['repository]['enabled'] not in ['yes', 'no']:
## UI_ask_to_enable_repo()
2013-08-11 15:22:07 +05:30
log_reader = apparmor . logparser . ReadLog ( pid , filename , existing_profiles , profile_dir , log )
log = log_reader . read_log ( logmark )
#read_log(logmark)
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
for root in log :
handle_children ( ' ' , ' ' , root )
2013-08-11 15:22:07 +05:30
#for root in range(len(log)):
#log[root] = handle_children('', '', log[root])
2013-09-22 22:51:30 +05:30
#print(log)
2013-07-28 08:23:46 +05:30
for pid in sorted ( profile_changes . keys ( ) ) :
set_process ( pid , profile_changes [ pid ] )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
collapse_log ( )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
ask_the_questions ( )
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
2013-07-28 08:23:46 +05:30
# To-Do
pass
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
finishing = False
# Check for finished
save_profiles ( )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
##if not repo_cfg['repository'].get('upload', False) or repo['repository']['upload'] == 'later':
## UI_ask_to_upload_profiles()
##if repo_enabled():
## if repo_cgf['repository']['upload'] == 'yes':
## sync_profiles()
## created = []
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
# If user selects 'Finish' then we want to exit logprof
if finishing :
return ' FINISHED '
else :
return ' NORMAL '
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
def save_profiles ( ) :
# Ensure the changed profiles are actual active profiles
for prof_name in changed . keys ( ) :
if not is_active_profile ( prof_name ) :
fix save_profile() by fixing some other code
When creating a child profile while using genprof, I get a backtrace:
Traceback (most recent call last):
File "aa-genprof", line 160, in <module>
lp_ret = apparmor.do_logprof_pass(logmark, passno)
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2291, in do_logprof_pass
save_profiles()
File "/home/cb/apparmor/HEAD-CLEAN/utils/apparmor/aa.py", line 2309, in save_profiles
for prof_name in changed.keys():
RuntimeError: dictionary changed size during iteration
(See https://bugs.launchpad.net/apparmor/+bug/1014304 for more details.)
After digging into the code, it seems for some reason the child profile
is added to "changed" - I doubt this is correct (guess why it's removed
later... ;-)
After digging a bit more, I found out that create_new_profile() is
(ab)used to create a new stub profile to be used as child profile.
create_new_profile then adds the new child (which looks like a normal
profile to it) to "changed".
This patch most probably makes the cleanup round in save_profile()
superfluous by adding a is_stub parameter to create_new_profile(). If
this parameter is set, the new (child) profile is not added to "created"
and "changed".
I intentionally added the two print() lines in safe_profile because
a) I think they will never be displayed
b) I want to know if a) is wrong ;-)
c) it's always nice to have a "nice" error message before displaying
a backtrace ;-)
Acked-by: Steve Beattie <steve@nxnw.org>
2014-06-10 00:44:59 +02:00
print ( " *** save_profiles(): removing %s " % prof_name )
print ( ' *** This should not happen. Please open a bugreport! ' )
2013-07-28 08:23:46 +05:30
changed . pop ( prof_name )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
changed_list = sorted ( changed . keys ( ) )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
if changed_list :
2013-09-22 22:51:30 +05:30
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
2013-07-28 08:23:46 +05:30
# To-Do
2014-02-13 10:52:00 -08:00
# selected_profiles = [] # XXX selected_profiles_ref?
2013-07-28 08:23:46 +05:30
profile_changes = dict ( )
for prof in changed_list :
oldprofile = serialize_profile ( original_aa [ prof ] , prof )
newprofile = serialize_profile ( aa [ prof ] , prof )
profile_changes [ prof ] = get_profile_diff ( oldprofile , newprofile )
2013-08-07 14:43:17 +05:30
explanation = _ ( ' Select which profile changes you would like to save to the \n local profile set. ' )
title = _ ( ' Local profile changes ' )
2014-02-10 22:20:36 -08:00
SendDataToYast ( { ' type ' : ' dialog-select-profiles ' ,
2013-07-28 08:23:46 +05:30
' title ' : title ,
' explanation ' : explanation ,
' dialog_select ' : ' true ' ,
' get_changelog ' : ' false ' ,
' profiles ' : profile_changes
} )
ypath , yarg = GetDataFromYast ( )
if yarg [ ' STATUS ' ] == ' cancel ' :
return None
else :
selected_profiles_ref = yarg [ ' PROFILES ' ]
for profile_name in selected_profiles_ref :
2013-07-31 19:56:33 +05:30
write_profile_ui_feedback ( profile_name )
2013-07-28 08:23:46 +05:30
reload_base ( profile_name )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
else :
2014-10-07 18:36:01 +05:30
q = aaui . PromptQuestion ( )
q . title = ' Changed Local Profiles '
q . explanation = _ ( ' The following local profiles were changed. Would you like to save them? ' )
q . functions = [ ' CMD_SAVE_CHANGES ' , ' CMD_SAVE_SELECTED ' , ' CMD_VIEW_CHANGES ' , ' CMD_VIEW_CHANGES_CLEAN ' , ' CMD_ABORT ' ]
q . default = ' CMD_VIEW_CHANGES '
q . options = changed
q . selected = 0
2013-07-28 08:23:46 +05:30
ans = ' '
arg = None
while ans != ' CMD_SAVE_CHANGES ' :
2013-09-22 15:01:34 +05:30
if not changed :
return
2014-10-07 18:36:01 +05:30
ans , arg = q . promptUser ( )
2013-08-21 11:26:09 +05:30
if ans == ' CMD_SAVE_SELECTED ' :
profile_name = list ( changed . keys ( ) ) [ arg ]
write_profile_ui_feedback ( profile_name )
reload_base ( profile_name )
2013-09-22 22:51:30 +05:30
2013-08-21 11:26:09 +05:30
elif ans == ' CMD_VIEW_CHANGES ' :
2013-08-18 14:13:46 +05:30
which = list ( changed . keys ( ) ) [ arg ]
oldprofile = None
if aa [ which ] [ which ] . get ( ' filename ' , False ) :
oldprofile = aa [ which ] [ which ] [ ' filename ' ]
else :
oldprofile = get_profile_filename ( which )
newprofile = serialize_profile_from_old_profile ( aa [ which ] , which , ' ' )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
display_changes_with_comments ( oldprofile , newprofile )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif ans == ' CMD_VIEW_CHANGES_CLEAN ' :
2013-08-17 12:34:42 +05:30
which = list ( changed . keys ( ) ) [ arg ]
2013-08-11 23:16:05 +05:30
oldprofile = serialize_profile ( original_aa [ which ] , which , ' ' )
newprofile = serialize_profile ( aa [ which ] , which , ' ' )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
display_changes ( oldprofile , newprofile )
2013-09-22 22:51:30 +05:30
2014-07-22 12:56:37 +02:00
for profile_name in sorted ( changed . keys ( ) ) :
2013-07-31 19:56:33 +05:30
write_profile_ui_feedback ( profile_name )
2013-07-28 08:23:46 +05:30
reload_base ( profile_name )
def get_pager ( ) :
pass
def generate_diff ( oldprofile , newprofile ) :
2013-08-18 14:13:46 +05:30
oldtemp = tempfile . NamedTemporaryFile ( ' w ' )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
oldtemp . write ( oldprofile )
oldtemp . flush ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
newtemp = tempfile . NamedTemporaryFile ( ' w ' )
2013-07-28 08:23:46 +05:30
newtemp . write ( newprofile )
newtemp . flush ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
difftemp = tempfile . NamedTemporaryFile ( ' w ' , delete = False )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
subprocess . call ( ' diff -u -p %s %s > %s ' % ( oldtemp . name , newtemp . name , difftemp . name ) , shell = True )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
oldtemp . close ( )
newtemp . close ( )
return difftemp
def get_profile_diff ( oldprofile , newprofile ) :
2013-09-22 22:51:30 +05:30
difftemp = generate_diff ( oldprofile , newprofile )
diff = [ ]
2013-07-28 08:23:46 +05:30
with open_file_read ( difftemp . name ) as f_in :
for line in f_in :
2013-07-30 20:13:08 +05:30
if not ( line . startswith ( ' --- ' ) and line . startswith ( ' +++ ' ) and line . startswith ( ' @@ ' ) ) :
2013-07-28 08:23:46 +05:30
diff . append ( line )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
difftemp . delete = True
difftemp . close ( )
return ' ' . join ( diff )
def display_changes ( oldprofile , newprofile ) :
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
aaui . UI_LongMessage ( _ ( ' Profile Changes ' ) , get_profile_diff ( oldprofile , newprofile ) )
2013-07-28 08:23:46 +05:30
else :
difftemp = generate_diff ( oldprofile , newprofile )
2014-02-10 22:20:36 -08:00
subprocess . call ( ' less %s ' % difftemp . name , shell = True )
2013-07-28 08:23:46 +05:30
difftemp . delete = True
difftemp . close ( )
2013-08-18 14:13:46 +05:30
def display_changes_with_comments ( oldprofile , newprofile ) :
""" Compare the new profile with the existing profile inclusive of all the comments """
if not os . path . exists ( oldprofile ) :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( " Can ' t find existing profile %s to compare changes. " ) % oldprofile )
2014-02-10 22:17:21 -08:00
if aaui . UI_mode == ' yast ' :
2013-08-18 14:13:46 +05:30
#To-Do
pass
else :
newtemp = tempfile . NamedTemporaryFile ( ' w ' )
newtemp . write ( newprofile )
newtemp . flush ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
difftemp = tempfile . NamedTemporaryFile ( ' w ' )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
subprocess . call ( ' diff -u -p %s %s > %s ' % ( oldprofile , newtemp . name , difftemp . name ) , shell = True )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
newtemp . close ( )
2014-02-10 22:20:36 -08:00
subprocess . call ( ' less %s ' % difftemp . name , shell = True )
2013-08-18 14:13:46 +05:30
difftemp . close ( )
2013-07-28 08:23:46 +05:30
def set_process ( pid , profile ) :
2013-07-30 20:13:08 +05:30
# If process not running don't do anything
if not os . path . exists ( ' /proc/ %s /attr/current ' % pid ) :
2013-07-28 08:23:46 +05:30
return None
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
process = None
try :
2013-07-30 20:13:08 +05:30
process = open_file_read ( ' /proc/ %s /attr/current ' % pid )
2013-07-28 08:23:46 +05:30
except IOError :
return None
current = process . readline ( ) . strip ( )
process . close ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not re . search ( ' ^null(-complain)*-profile$ ' , current ) :
2013-07-28 08:23:46 +05:30
return None
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
stats = None
try :
stats = open_file_read ( ' /proc/ %s /stat ' % pid )
except IOError :
return None
stat = stats . readline ( ) . strip ( )
stats . close ( )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
match = re . search ( ' ^ \ d+ \ (( \ S+) \ ) ' , stat )
if not match :
return None
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
try :
process = open_file_write ( ' /proc/ %s /attr/current ' % pid )
except IOError :
return None
process . write ( ' setprofile %s ' % profile )
process . close ( )
def collapse_log ( ) :
for aamode in prelog . keys ( ) :
for profile in prelog [ aamode ] . keys ( ) :
for hat in prelog [ aamode ] [ profile ] . keys ( ) :
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
for path in prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] . keys ( ) :
mode = prelog [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ]
2013-09-22 22:51:30 +05:30
2013-08-11 23:16:05 +05:30
combinedmode = set ( )
2013-07-28 08:23:46 +05:30
# Is path in original profile?
if aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] . get ( path , False ) :
2013-09-22 15:01:34 +05:30
combinedmode | = aa [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] [ path ] [ ' mode ' ]
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
# Match path to regexps in profile
2013-08-11 15:22:07 +05:30
combinedmode | = rematchfrag ( aa [ profile ] [ hat ] , ' allow ' , path ) [ 0 ]
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
# Match path from includes
2013-08-11 23:16:05 +05:30
2013-08-11 15:22:07 +05:30
combinedmode | = match_prof_incs_to_path ( aa [ profile ] [ hat ] , ' allow ' , path ) [ 0 ]
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
if not combinedmode or not mode_contains ( combinedmode , mode ) :
2013-08-11 15:22:07 +05:30
if log_dict [ aamode ] [ profile ] [ hat ] [ ' path ' ] . get ( path , False ) :
mode | = log_dict [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ]
2013-09-22 22:51:30 +05:30
2013-08-11 15:22:07 +05:30
log_dict [ aamode ] [ profile ] [ hat ] [ ' path ' ] [ path ] = mode
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
for capability in prelog [ aamode ] [ profile ] [ hat ] [ ' capability ' ] . keys ( ) :
# If capability not already in profile
if not aa [ profile ] [ hat ] [ ' allow ' ] [ ' capability ' ] [ capability ] . get ( ' set ' , False ) :
2013-08-11 15:22:07 +05:30
log_dict [ aamode ] [ profile ] [ hat ] [ ' capability ' ] [ capability ] = True
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
nd = prelog [ aamode ] [ profile ] [ hat ] [ ' netdomain ' ]
for family in nd . keys ( ) :
for sock_type in nd [ family ] . keys ( ) :
if not profile_known_network ( aa [ profile ] [ hat ] , family , sock_type ) :
2013-08-11 15:22:07 +05:30
log_dict [ aamode ] [ profile ] [ hat ] [ ' netdomain ' ] [ family ] [ sock_type ] = True
2013-07-28 08:23:46 +05:30
def validate_profile_mode ( mode , allow , nt_name = None ) :
if allow == ' deny ' :
pattern = ' ^( %s )+$ ' % PROFILE_MODE_DENY_RE . pattern
if re . search ( pattern , mode ) :
return True
else :
return False
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
elif nt_name :
pattern = ' ^( %s )+$ ' % PROFILE_MODE_NT_RE . pattern
if re . search ( pattern , mode ) :
return True
else :
return False
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
else :
pattern = ' ^( %s )+$ ' % PROFILE_MODE_RE . pattern
if re . search ( pattern , mode ) :
return True
else :
return False
2015-02-04 13:18:47 +01:00
2013-07-28 08:23:46 +05:30
def is_skippable_file ( path ) :
2015-02-04 13:18:47 +01:00
""" Returns True if filename matches something to be skipped (rpm or dpkg backup files, hidden files etc.)
The list of skippable files needs to be synced with apparmor initscript and libapparmor _aa_is_blacklisted ( )
path : filename ( with or without directory ) """
basename = os . path . basename ( path )
if not basename or basename [ 0 ] == ' . ' or basename == ' README ' :
2013-07-28 08:23:46 +05:30
return True
2015-02-04 13:18:47 +01:00
skippable_suffix = ( ' .dpkg-new ' , ' .dpkg-old ' , ' .dpkg-dist ' , ' .dpkg-bak ' , ' .rpmnew ' , ' .rpmsave ' , ' .orig ' , ' .rej ' , ' ~ ' )
if basename . endswith ( skippable_suffix ) :
return True
return False
2013-07-28 08:23:46 +05:30
def is_skippable_dir ( path ) :
2013-08-30 03:54:31 +05:30
if re . search ( ' (disable|cache|force-complain|lxc) ' , path ) :
2013-07-28 08:23:46 +05:30
return True
return False
def check_include_syntax ( errors ) :
# To-Do
pass
def check_profile_syntax ( errors ) :
# To-Do
pass
2013-08-18 14:13:46 +05:30
def read_profiles ( ) :
2013-07-28 08:23:46 +05:30
try :
os . listdir ( profile_dir )
2014-02-10 22:20:36 -08:00
except :
2013-09-21 01:08:34 +05:30
fatal_error ( _ ( " Can ' t read AppArmor profiles in %s " ) % profile_dir )
2013-08-13 00:43:20 +05:30
2013-07-28 08:23:46 +05:30
for file in os . listdir ( profile_dir ) :
if os . path . isfile ( profile_dir + ' / ' + file ) :
if is_skippable_file ( file ) :
continue
else :
2013-08-18 14:13:46 +05:30
read_profile ( profile_dir + ' / ' + file , True )
2013-07-28 08:23:46 +05:30
def read_inactive_profiles ( ) :
if not os . path . exists ( extra_profile_dir ) :
return None
try :
os . listdir ( profile_dir )
2014-02-10 22:20:36 -08:00
except :
2013-09-21 01:08:34 +05:30
fatal_error ( _ ( " Can ' t read AppArmor profiles in %s " ) % extra_profile_dir )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
for file in os . listdir ( profile_dir ) :
if os . path . isfile ( extra_profile_dir + ' / ' + file ) :
if is_skippable_file ( file ) :
continue
else :
read_profile ( extra_profile_dir + ' / ' + file , False )
def read_profile ( file , active_profile ) :
data = None
try :
with open_file_read ( file ) as f_in :
data = f_in . readlines ( )
except IOError :
2014-02-10 22:20:36 -08:00
debug_logger . debug ( " read_profile: can ' t read %s - skipping " % file )
2013-07-28 08:23:46 +05:30
return None
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
profile_data = parse_profile_data ( data , file , 0 )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
if profile_data and active_profile :
attach_profile_data ( aa , profile_data )
attach_profile_data ( original_aa , profile_data )
elif profile_data :
attach_profile_data ( extras , profile_data )
2013-09-22 22:51:30 +05:30
2013-07-28 08:23:46 +05:30
def attach_profile_data ( profiles , profile_data ) :
2013-09-22 22:51:30 +05:30
# Make deep copy of data to avoid changes to
2013-07-28 08:23:46 +05:30
# arising due to mutables
for p in profile_data . keys ( ) :
profiles [ p ] = deepcopy ( profile_data [ p ] )
2013-07-30 20:13:08 +05:30
2015-03-02 21:46:45 +01:00
def parse_profile_start ( line , file , lineno , profile , hat ) :
2015-04-13 18:24:20 -07:00
matches = parse_profile_start_line ( line , file )
2015-03-02 21:46:45 +01:00
2015-04-13 18:49:37 -07:00
if profile : # we are inside a profile, so we expect a child profile
if not matches [ ' profile_keyword ' ] :
raise AppArmorException ( _ ( ' %(profile)s profile in %(file)s contains syntax errors in line %(line)s : missing " profile " keyword. ' ) % {
' profile ' : profile , ' file ' : file , ' line ' : lineno + 1 } )
if profile != hat :
# nesting limit reached - a child profile can't contain another child profile
raise AppArmorException ( _ ( ' %(profile)s profile in %(file)s contains syntax errors in line %(line)s : a child profile inside another child profile is not allowed. ' ) % {
' profile ' : profile , ' file ' : file , ' line ' : lineno + 1 } )
2015-04-13 18:24:20 -07:00
hat = matches [ ' profile ' ]
2015-03-02 21:46:45 +01:00
in_contained_hat = True
pps_set_profile = True
2015-04-13 18:49:37 -07:00
pps_set_hat_external = False
else : # stand-alone profile
2015-04-13 18:24:20 -07:00
profile = matches [ ' profile ' ]
2015-03-02 21:46:45 +01:00
if len ( profile . split ( ' // ' ) ) > = 2 :
profile , hat = profile . split ( ' // ' ) [ : 2 ]
pps_set_hat_external = True
else :
hat = profile
2015-04-13 18:49:37 -07:00
pps_set_hat_external = False
in_contained_hat = False
pps_set_profile = False
2015-03-02 21:46:45 +01:00
2015-04-13 18:36:42 -07:00
attachment = matches [ ' attachment ' ]
2015-04-13 18:24:20 -07:00
flags = matches [ ' flags ' ]
2015-03-02 21:46:45 +01:00
2015-04-13 18:36:42 -07:00
return ( profile , hat , attachment , flags , in_contained_hat , pps_set_profile , pps_set_hat_external )
2015-03-02 21:46:45 +01:00
2013-07-30 20:13:08 +05:30
def parse_profile_data ( data , file , do_include ) :
profile_data = hasher ( )
profile = None
hat = None
in_contained_hat = None
repo_data = None
parsed_profiles = [ ]
initial_comment = ' '
utils: add simple parsing of multi-line rules [v3]
D-Bus rules in particular seem to get written as multi-line rules. This
patch adds very simple hackish support for multiple lines. Essentially,
what it does is if the parsing of a line doesn't match anything and
falls all the way through, it saves the line and prepends it to the next
line that occurs in the profile, but *only* if the line does not have a
trailing comma to indicate the end of a rule. If the trailing comma
exists, then it assumes that it's a rule that it doesn't understand and
aborts.
With this patch, the simpler tools (aa-enforce, aa-complain, etc.) can
parse policies containing multi-line rules to an extent and continue to
function correctly. Again, aa-logprof and aa-genprof may have issues on
the writing back of profiles, so some assistance testing here would be
appreciated.
Some testcases are added to exercise the regex that looks for a rule
with a trailing comma but can still handle rules that have (,) or {,}
in them.
Patch history:
v1 - initial version
v2 - simplify and rearrange rule-ending comma search regex, since
we only care about the trailing comma
- add a new regex to search for trailing comments to filter out
- simplify reset of lastline variable
- restructure tests into a new script, and add more tests
v3 - add additional testcases, most of which are problematic and thus
commented out :(
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2014-03-07 10:04:57 -08:00
lastline = None
2013-08-18 14:13:46 +05:30
2013-07-30 20:13:08 +05:30
if do_include :
profile = file
hat = file
for lineno , line in enumerate ( data ) :
line = line . strip ( )
if not line :
continue
utils: add simple parsing of multi-line rules [v3]
D-Bus rules in particular seem to get written as multi-line rules. This
patch adds very simple hackish support for multiple lines. Essentially,
what it does is if the parsing of a line doesn't match anything and
falls all the way through, it saves the line and prepends it to the next
line that occurs in the profile, but *only* if the line does not have a
trailing comma to indicate the end of a rule. If the trailing comma
exists, then it assumes that it's a rule that it doesn't understand and
aborts.
With this patch, the simpler tools (aa-enforce, aa-complain, etc.) can
parse policies containing multi-line rules to an extent and continue to
function correctly. Again, aa-logprof and aa-genprof may have issues on
the writing back of profiles, so some assistance testing here would be
appreciated.
Some testcases are added to exercise the regex that looks for a rule
with a trailing comma but can still handle rules that have (,) or {,}
in them.
Patch history:
v1 - initial version
v2 - simplify and rearrange rule-ending comma search regex, since
we only care about the trailing comma
- add a new regex to search for trailing comments to filter out
- simplify reset of lastline variable
- restructure tests into a new script, and add more tests
v3 - add additional testcases, most of which are problematic and thus
commented out :(
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2014-03-07 10:04:57 -08:00
# we're dealing with a multiline statement
if lastline :
line = ' %s %s ' % ( lastline , line )
lastline = None
2013-07-30 20:13:08 +05:30
# Starting line of a profile
if RE_PROFILE_START . search ( line ) :
2015-04-13 18:36:42 -07:00
( profile , hat , attachment , flags , in_contained_hat , pps_set_profile , pps_set_hat_external ) = parse_profile_start ( line , file , lineno , profile , hat )
2015-03-02 21:46:45 +01:00
if pps_set_profile :
2014-02-10 22:20:36 -08:00
profile_data [ profile ] [ hat ] [ ' profile ' ] = True
2015-03-02 21:46:45 +01:00
if pps_set_hat_external :
profile_data [ profile ] [ hat ] [ ' external ' ] = True
2013-08-21 11:26:09 +05:30
# Profile stored
existing_profiles [ profile ] = file
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
# save profile name and filename
profile_data [ profile ] [ hat ] [ ' name ' ] = profile
profile_data [ profile ] [ hat ] [ ' filename ' ] = file
filelist [ file ] [ ' profiles ' ] [ profile ] [ hat ] = True
2013-08-13 00:43:20 +05:30
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ ' flags ' ] = flags
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' netdomain ' ] = hasher ( )
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' path ' ] = hasher ( )
2014-03-07 09:58:54 -08:00
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' dbus ' ] = list ( )
2014-03-20 14:25:42 -05:00
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' mount ' ] = list ( )
2014-04-23 15:39:14 -05:00
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' signal ' ] = list ( )
2014-04-23 15:40:20 -05:00
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' ptrace ' ] = list ( )
2014-04-23 15:41:03 -05:00
profile_data [ profile ] [ hat ] [ ' allow ' ] [ ' pivot_root ' ] = list ( )
2013-07-30 20:13:08 +05:30
# Save the initial comment
if initial_comment :
profile_data [ profile ] [ hat ] [ ' initial_comment ' ] = initial_comment
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
initial_comment = ' '
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if repo_data :
profile_data [ profile ] [ profile ] [ ' repo ' ] [ ' url ' ] = repo_data [ ' url ' ]
profile_data [ profile ] [ profile ] [ ' repo ' ] [ ' user ' ] = repo_data [ ' user ' ]
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_END . search ( line ) :
# If profile ends and we're not in one
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected End of Profile reached in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if in_contained_hat :
hat = profile
in_contained_hat = False
else :
parsed_profiles . append ( profile )
profile = None
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
initial_comment = ' '
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_CAP . search ( line ) :
2014-10-01 21:45:22 +02:00
matches = RE_PROFILE_CAP . search ( line )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected capability entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2014-11-08 16:47:39 +01:00
audit , allow , allow_keyword , comment = parse_audit_allow ( matches )
# TODO: honor allow_keyword and comment
2013-09-22 22:51:30 +05:30
2014-03-20 14:27:24 -05:00
capability = ALL
2014-10-01 21:45:22 +02:00
if matches . group ( ' capability ' ) :
capability = matches . group ( ' capability ' ) . strip ( )
# TODO: can contain more than one capability- split it?
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' capability ' ] [ capability ] [ ' set ' ] = True
profile_data [ profile ] [ hat ] [ allow ] [ ' capability ' ] [ capability ] [ ' audit ' ] = audit
2013-09-22 22:51:30 +05:30
2013-08-06 01:53:28 +05:30
elif RE_PROFILE_LINK . search ( line ) :
2013-07-30 20:13:08 +05:30
matches = RE_PROFILE_LINK . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected link entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
audit = False
if matches [ 0 ] :
audit = True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
allow = ' allow '
2013-08-09 16:49:01 +05:30
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
2013-07-30 20:13:08 +05:30
allow = ' deny '
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
subset = matches [ 3 ]
link = strip_quotes ( matches [ 6 ] )
value = strip_quotes ( matches [ 7 ] )
profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' to ' ] = value
2014-02-10 22:17:21 -08:00
profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' mode ' ] = profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] . get ( ' mode ' , set ( ) ) | apparmor . aamode . AA_MAY_LINK
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if subset :
2014-02-10 22:17:21 -08:00
profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' mode ' ] | = apparmor . aamode . AA_LINK_SUBSET
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if audit :
2014-02-10 22:17:21 -08:00
profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' audit ' ] = profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] . get ( ' audit ' , set ( ) ) | apparmor . aamode . AA_LINK_SUBSET
2013-07-30 20:13:08 +05:30
else :
2013-08-11 23:16:05 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' audit ' ] = set ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_CHANGE_PROFILE . search ( line ) :
matches = RE_PROFILE_CHANGE_PROFILE . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected change profile entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
cp = strip_quotes ( matches [ 0 ] )
2014-11-29 13:40:10 +01:00
profile_data [ profile ] [ hat ] [ ' change_profile ' ] [ cp ] = True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_ALIAS . search ( line ) :
matches = RE_PROFILE_ALIAS . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
from_name = strip_quotes ( matches [ 0 ] )
to_name = strip_quotes ( matches [ 1 ] )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if profile :
profile_data [ profile ] [ hat ] [ ' alias ' ] [ from_name ] = to_name
else :
if not filelist . get ( file , False ) :
filelist [ file ] = hasher ( )
filelist [ file ] [ ' alias ' ] [ from_name ] = to_name
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_RLIMIT . search ( line ) :
matches = RE_PROFILE_RLIMIT . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected rlimit entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
from_name = matches [ 0 ]
2013-08-09 16:49:01 +05:30
to_name = matches [ 2 ]
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ ' rlimit ' ] [ from_name ] = to_name
2013-09-22 22:51:30 +05:30
2013-08-06 01:53:28 +05:30
elif RE_PROFILE_BOOLEAN . search ( line ) :
matches = RE_PROFILE_BOOLEAN . search ( line )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected boolean definition found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
bool_var = matches [ 0 ]
value = matches [ 1 ]
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ ' lvar ' ] [ bool_var ] = value
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_VARIABLE . search ( line ) :
2013-09-22 22:51:30 +05:30
# variable additions += and =
2013-08-06 01:53:28 +05:30
matches = RE_PROFILE_VARIABLE . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
list_var = strip_quotes ( matches [ 0 ] )
2013-08-06 01:53:28 +05:30
var_operation = matches [ 1 ]
value = strip_quotes ( matches [ 2 ] )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if profile :
if not profile_data [ profile ] [ hat ] . get ( ' lvar ' , False ) :
profile_data [ profile ] [ hat ] [ ' lvar ' ] [ list_var ] = [ ]
2014-06-20 13:36:35 +02:00
store_list_var ( profile_data [ profile ] [ ' lvar ' ] , list_var , value , var_operation , file )
2013-07-30 20:13:08 +05:30
else :
if not filelist [ file ] . get ( ' lvar ' , False ) :
filelist [ file ] [ ' lvar ' ] [ list_var ] = [ ]
2014-06-20 13:36:35 +02:00
store_list_var ( filelist [ file ] [ ' lvar ' ] , list_var , value , var_operation , file )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_CONDITIONAL . search ( line ) :
# Conditional Boolean
pass
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_CONDITIONAL_VARIABLE . search ( line ) :
# Conditional Variable defines
pass
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_CONDITIONAL_BOOLEAN . search ( line ) :
# Conditional Boolean defined
pass
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
elif RE_PROFILE_BARE_FILE_ENTRY . search ( line ) :
2014-10-08 12:31:56 +02:00
matches = RE_PROFILE_BARE_FILE_ENTRY . search ( line )
2014-04-23 16:28:17 -05:00
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected bare file rule found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-04-23 16:28:17 -05:00
2014-11-08 16:47:39 +01:00
audit , allow , allow_keyword , comment = parse_audit_allow ( matches )
# TODO: honor allow_keyword and comment
2014-04-23 16:28:17 -05:00
mode = apparmor . aamode . AA_BARE_FILE_MODE
2014-10-08 12:31:56 +02:00
if not matches . group ( ' owner ' ) :
2014-04-23 16:28:17 -05:00
mode | = AA_OTHER ( apparmor . aamode . AA_BARE_FILE_MODE )
path_rule = profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ ALL ]
path_rule [ ' mode ' ] = mode
2014-10-08 12:31:56 +02:00
path_rule [ ' audit ' ] = set ( )
if audit :
path_rule [ ' audit ' ] = mode
2014-04-23 16:28:17 -05:00
path_rule [ ' file_prefix ' ] = True
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_PATH_ENTRY . search ( line ) :
matches = RE_PROFILE_PATH_ENTRY . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected path entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
audit = False
if matches [ 0 ] :
audit = True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
allow = ' allow '
2013-08-09 16:49:01 +05:30
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
2013-07-30 20:13:08 +05:30
allow = ' deny '
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
user = False
if matches [ 2 ] :
user = True
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
file_prefix = False
if matches [ 3 ] :
file_prefix = True
2014-10-11 23:30:46 +02:00
path = strip_quotes ( matches [ 4 ] . strip ( ) )
2014-04-23 16:28:17 -05:00
mode = matches [ 5 ]
2015-04-11 02:16:08 +02:00
nt_name = matches [ 7 ]
2013-07-30 20:13:08 +05:30
if nt_name :
nt_name = nt_name . strip ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
p_re = convert_regexp ( path )
try :
re . compile ( p_re )
except :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Invalid Regex %(path)s in file: %(file)s line: %(line)s ' ) % { ' path ' : path , ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not validate_profile_mode ( mode , allow , nt_name ) :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Invalid mode %(mode)s in file: %(file)s line: %(line)s ' ) % { ' mode ' : mode , ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-08-11 23:16:05 +05:30
tmpmode = set ( )
2013-07-30 20:13:08 +05:30
if user :
tmpmode = str_to_mode ( ' %s :: ' % mode )
else :
tmpmode = str_to_mode ( mode )
2013-09-22 22:51:30 +05:30
2013-08-11 23:16:05 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' mode ' ] = profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' mode ' , set ( ) ) | tmpmode
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
if file_prefix :
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' file_prefix ' ] = True
2014-04-03 21:58:59 -05:00
if nt_name :
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' to ' ] = nt_name
if audit :
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' audit ' ] = profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' audit ' , set ( ) ) | tmpmode
else :
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' audit ' ] = set ( )
2013-07-30 20:13:08 +05:30
elif re_match_include ( line ) :
# Include files
2013-08-18 14:13:46 +05:30
include_name = re_match_include ( line )
2013-08-30 03:54:31 +05:30
if include_name . startswith ( ' local/ ' ) :
profile_data [ profile ] [ hat ] [ ' localinclude ' ] [ include_name ] = True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if profile :
2013-08-18 14:13:46 +05:30
profile_data [ profile ] [ hat ] [ ' include ' ] [ include_name ] = True
2013-07-30 20:13:08 +05:30
else :
if not filelist . get ( file ) :
filelist [ file ] = hasher ( )
2013-08-18 14:13:46 +05:30
filelist [ file ] [ ' include ' ] [ include_name ] = True
2013-07-30 20:13:08 +05:30
# If include is a directory
2013-08-18 14:13:46 +05:30
if os . path . isdir ( profile_dir + ' / ' + include_name ) :
for path in os . listdir ( profile_dir + ' / ' + include_name ) :
2013-07-30 20:13:08 +05:30
path = path . strip ( )
if is_skippable_file ( path ) :
continue
2013-08-18 14:13:46 +05:30
if os . path . isfile ( profile_dir + ' / ' + include_name + ' / ' + path ) :
file_name = include_name + ' / ' + path
2014-02-10 22:20:36 -08:00
file_name = file_name . replace ( profile_dir + ' / ' , ' ' )
2013-08-18 14:13:46 +05:30
if not include . get ( file_name , False ) :
load_include ( file_name )
2013-07-30 20:13:08 +05:30
else :
2013-08-18 14:13:46 +05:30
if not include . get ( include_name , False ) :
load_include ( include_name )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_NETWORK . search ( line ) :
matches = RE_PROFILE_NETWORK . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected network entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
2013-08-09 16:49:01 +05:30
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
2013-07-30 20:13:08 +05:30
allow = ' deny '
network = matches [ 2 ]
2013-08-18 14:13:46 +05:30
2013-08-09 16:49:01 +05:30
if RE_NETWORK_FAMILY_TYPE . search ( network ) :
nmatch = RE_NETWORK_FAMILY_TYPE . search ( network ) . groups ( )
2013-07-30 20:13:08 +05:30
fam , typ = nmatch [ : 2 ]
2013-09-23 03:47:15 +05:30
##Simply ignore any type subrules if family has True (seperately for allow and deny)
##This will lead to those type specific rules being lost when written
#if type(profile_data[profile][hat][allow]['netdomain']['rule'].get(fam, False)) == dict:
2014-02-10 22:20:36 -08:00
profile_data [ profile ] [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] [ typ ] = 1
2013-09-23 03:47:15 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] [ typ ] = audit
2013-08-09 16:49:01 +05:30
elif RE_NETWORK_FAMILY . search ( network ) :
fam = RE_NETWORK_FAMILY . search ( network ) . groups ( ) [ 0 ]
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] = True
profile_data [ profile ] [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] = audit
else :
profile_data [ profile ] [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ ' all ' ] = True
2014-02-10 22:20:36 -08:00
profile_data [ profile ] [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ ' all ' ] = audit # True
2013-09-22 22:51:30 +05:30
2014-03-07 09:58:54 -08:00
elif RE_PROFILE_DBUS . search ( line ) :
matches = RE_PROFILE_DBUS . search ( line ) . groups ( )
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected dbus entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-03-07 09:58:54 -08:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
dbus = matches [ 2 ]
#parse_dbus_rule(profile_data[profile], dbus, audit, allow)
dbus_rule = parse_dbus_rule ( dbus )
dbus_rule . audit = audit
dbus_rule . deny = ( allow == ' deny ' )
dbus_rules = profile_data [ profile ] [ hat ] [ allow ] . get ( ' dbus ' , list ( ) )
dbus_rules . append ( dbus_rule )
profile_data [ profile ] [ hat ] [ allow ] [ ' dbus ' ] = dbus_rules
2014-03-20 14:25:42 -05:00
elif RE_PROFILE_MOUNT . search ( line ) :
matches = RE_PROFILE_MOUNT . search ( line ) . groups ( )
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected mount entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-03-20 14:25:42 -05:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
mount = matches [ 2 ]
mount_rule = parse_mount_rule ( mount )
mount_rule . audit = audit
mount_rule . deny = ( allow == ' deny ' )
mount_rules = profile_data [ profile ] [ hat ] [ allow ] . get ( ' mount ' , list ( ) )
mount_rules . append ( mount_rule )
profile_data [ profile ] [ hat ] [ allow ] [ ' mount ' ] = mount_rules
2014-04-23 15:39:14 -05:00
elif RE_PROFILE_SIGNAL . search ( line ) :
matches = RE_PROFILE_SIGNAL . search ( line ) . groups ( )
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected signal entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-04-23 15:39:14 -05:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
signal = matches [ 2 ] . strip ( )
signal_rule = parse_signal_rule ( signal )
signal_rule . audit = audit
signal_rule . deny = ( allow == ' deny ' )
signal_rules = profile_data [ profile ] [ hat ] [ allow ] . get ( ' signal ' , list ( ) )
signal_rules . append ( signal_rule )
profile_data [ profile ] [ hat ] [ allow ] [ ' signal ' ] = signal_rules
2014-04-23 15:40:20 -05:00
elif RE_PROFILE_PTRACE . search ( line ) :
matches = RE_PROFILE_PTRACE . search ( line ) . groups ( )
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected ptrace entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-04-23 15:40:20 -05:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
ptrace = matches [ 2 ] . strip ( )
ptrace_rule = parse_ptrace_rule ( ptrace )
ptrace_rule . audit = audit
ptrace_rule . deny = ( allow == ' deny ' )
ptrace_rules = profile_data [ profile ] [ hat ] [ allow ] . get ( ' ptrace ' , list ( ) )
ptrace_rules . append ( ptrace_rule )
profile_data [ profile ] [ hat ] [ allow ] [ ' ptrace ' ] = ptrace_rules
2014-04-23 15:41:03 -05:00
elif RE_PROFILE_PIVOT_ROOT . search ( line ) :
matches = RE_PROFILE_PIVOT_ROOT . search ( line ) . groups ( )
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected pivot_root entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-04-23 15:41:03 -05:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
pivot_root = matches [ 2 ] . strip ( )
pivot_root_rule = parse_pivot_root_rule ( pivot_root )
pivot_root_rule . audit = audit
pivot_root_rule . deny = ( allow == ' deny ' )
pivot_root_rules = profile_data [ profile ] [ hat ] [ allow ] . get ( ' pivot_root ' , list ( ) )
pivot_root_rules . append ( pivot_root_rule )
profile_data [ profile ] [ hat ] [ allow ] [ ' pivot_root ' ] = pivot_root_rules
2014-09-03 18:18:33 -07:00
elif RE_PROFILE_UNIX . search ( line ) :
matches = RE_PROFILE_UNIX . search ( line ) . groups ( )
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected unix entry found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2014-09-03 18:18:33 -07:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
unix = matches [ 2 ] . strip ( )
unix_rule = parse_unix_rule ( unix )
unix_rule . audit = audit
unix_rule . deny = ( allow == ' deny ' )
unix_rules = profile_data [ profile ] [ hat ] [ allow ] . get ( ' unix ' , list ( ) )
unix_rules . append ( unix_rule )
profile_data [ profile ] [ hat ] [ allow ] [ ' unix ' ] = unix_rules
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_CHANGE_HAT . search ( line ) :
matches = RE_PROFILE_CHANGE_HAT . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected change hat declaration found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
hat = matches [ 0 ]
hat = strip_quotes ( hat )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile_data [ profile ] [ hat ] . get ( ' declared ' , False ) :
profile_data [ profile ] [ hat ] [ ' declared ' ] = True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif RE_PROFILE_HAT_DEF . search ( line ) :
# An embedded hat syntax definition starts
2014-10-16 22:03:42 +02:00
matches = RE_PROFILE_HAT_DEF . search ( line )
2013-07-30 20:13:08 +05:30
if not profile :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unexpected hat definition found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
in_contained_hat = True
2014-10-16 22:03:42 +02:00
hat = matches . group ( ' hat ' )
2013-07-30 20:13:08 +05:30
hat = strip_quotes ( hat )
2014-10-16 22:03:42 +02:00
flags = matches . group ( ' flags ' )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
profile_data [ profile ] [ hat ] [ ' flags ' ] = flags
profile_data [ profile ] [ hat ] [ ' declared ' ] = False
#profile_data[profile][hat]['allow']['path'] = hasher()
#profile_data[profile][hat]['allow']['netdomain'] = hasher()
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if initial_comment :
profile_data [ profile ] [ hat ] [ ' initial_comment ' ] = initial_comment
initial_comment = ' '
2013-08-09 16:49:01 +05:30
if filelist [ file ] [ ' profiles ' ] [ profile ] . get ( hat , False ) :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Error: Multiple definitions for hat %(hat)s in profile %(profile)s . ' ) % { ' hat ' : hat , ' profile ' : profile } )
2013-07-30 20:13:08 +05:30
filelist [ file ] [ ' profiles ' ] [ profile ] [ hat ] = True
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
elif line [ 0 ] == ' # ' :
# Handle initial comments
if not profile :
2014-02-22 13:09:15 +01:00
if line . startswith ( ' # Last Modified: ' ) :
2013-07-30 20:13:08 +05:30
continue
2014-02-24 19:20:11 +01:00
elif line . startswith ( ' # REPOSITORY: ' ) : # TODO: allow any number of spaces/tabs
parts = line . split ( )
if len ( parts ) == 3 and parts [ 2 ] == ' NEVERSUBMIT ' :
2013-07-30 20:13:08 +05:30
repo_data = { ' neversubmit ' : True }
2014-02-24 19:20:11 +01:00
elif len ( parts ) == 5 :
repo_data = { ' url ' : parts [ 2 ] ,
' user ' : parts [ 3 ] ,
' id ' : parts [ 4 ] }
else :
aaui . UI_Important ( _ ( ' Warning: invalid " REPOSITORY: " line in %s , ignoring. ' ) % file )
initial_comment = initial_comment + line + ' \n '
2013-07-30 20:13:08 +05:30
else :
2014-02-22 13:09:15 +01:00
initial_comment = initial_comment + line + ' \n '
2013-09-22 22:51:30 +05:30
utils: add simple parsing of multi-line rules [v3]
D-Bus rules in particular seem to get written as multi-line rules. This
patch adds very simple hackish support for multiple lines. Essentially,
what it does is if the parsing of a line doesn't match anything and
falls all the way through, it saves the line and prepends it to the next
line that occurs in the profile, but *only* if the line does not have a
trailing comma to indicate the end of a rule. If the trailing comma
exists, then it assumes that it's a rule that it doesn't understand and
aborts.
With this patch, the simpler tools (aa-enforce, aa-complain, etc.) can
parse policies containing multi-line rules to an extent and continue to
function correctly. Again, aa-logprof and aa-genprof may have issues on
the writing back of profiles, so some assistance testing here would be
appreciated.
Some testcases are added to exercise the regex that looks for a rule
with a trailing comma but can still handle rules that have (,) or {,}
in them.
Patch history:
v1 - initial version
v2 - simplify and rearrange rule-ending comma search regex, since
we only care about the trailing comma
- add a new regex to search for trailing comments to filter out
- simplify reset of lastline variable
- restructure tests into a new script, and add more tests
v3 - add additional testcases, most of which are problematic and thus
commented out :(
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2014-03-07 10:04:57 -08:00
elif not RE_RULE_HAS_COMMA . search ( line ) :
# Bah, line continues on to the next line
if RE_HAS_COMMENT_SPLIT . search ( line ) :
# filter trailing comments
lastline = RE_HAS_COMMENT_SPLIT . search ( line ) . group ( ' not_comment ' )
else :
lastline = line
2013-07-30 20:13:08 +05:30
else :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Syntax Error: Unknown line found in file: %(file)s line: %(line)s ' ) % { ' file ' : file , ' line ' : lineno + 1 } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
# Below is not required I'd say
if not do_include :
for hatglob in cfg [ ' required_hats ' ] . keys ( ) :
for parsed_prof in sorted ( parsed_profiles ) :
if re . search ( hatglob , parsed_prof ) :
for hat in cfg [ ' required_hats ' ] [ hatglob ] . split ( ) :
if not profile_data [ parsed_prof ] . get ( hat , False ) :
profile_data [ parsed_prof ] [ hat ] = hasher ( )
2013-09-22 22:51:30 +05:30
# End of file reached but we're stuck in a profile
2013-07-30 20:13:08 +05:30
if profile and not do_include :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( " Syntax Error: Missing ' } ' or ' , ' . Reached end of file %(file)s while inside profile %(profile)s " ) % { ' file ' : file , ' profile ' : profile } )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return profile_data
2014-10-01 21:45:22 +02:00
def parse_audit_allow ( matches ) :
audit = False
if matches . group ( ' audit ' ) :
audit = True
allow = ' allow '
allow_keyword = False
if matches . group ( ' allow ' ) :
allow = matches . group ( ' allow ' ) . strip ( )
allow_keyword = True
if allow != ' allow ' and allow != ' deny ' : # should never happen
raise AppArmorException ( _ ( " Invalid allow/deny keyword %s " % allow ) )
2014-11-08 16:47:39 +01:00
comment = ' '
if matches . group ( ' comment ' ) :
# include a space so that we don't need to add it everywhere when writing the rule
comment = ' %s ' % matches . group ( ' comment ' )
return ( audit , allow , allow_keyword , comment )
2014-10-01 21:45:22 +02:00
2014-03-07 09:58:54 -08:00
# RE_DBUS_ENTRY = re.compile('^dbus\s*()?,\s*$')
# use stuff like '(?P<action>(send|write|w|receive|read|r|rw))'
def parse_dbus_rule ( line ) :
# XXX Do real parsing here
return aarules . Raw_DBUS_Rule ( line )
#matches = RE_DBUS_ENTRY.search(line).groups()
#if len(matches) == 1:
# XXX warn?
# matched nothing
# print('no matches')
# return aarules.DBUS_Rule()
#print(line)
2014-03-20 14:25:42 -05:00
def parse_mount_rule ( line ) :
# XXX Do real parsing here
return aarules . Raw_Mount_Rule ( line )
2014-04-23 15:39:14 -05:00
def parse_signal_rule ( line ) :
# XXX Do real parsing here
return aarules . Raw_Signal_Rule ( line )
2014-04-23 15:40:20 -05:00
def parse_ptrace_rule ( line ) :
# XXX Do real parsing here
return aarules . Raw_Ptrace_Rule ( line )
2014-04-23 15:41:03 -05:00
def parse_pivot_root_rule ( line ) :
# XXX Do real parsing here
return aarules . Raw_Pivot_Root_Rule ( line )
2014-09-03 18:18:33 -07:00
def parse_unix_rule ( line ) :
# XXX Do real parsing here
return aarules . Raw_Unix_Rule ( line )
2013-07-30 20:13:08 +05:30
def separate_vars ( vs ) :
2013-08-09 16:49:01 +05:30
""" Returns a list of all the values for a variable """
2013-07-30 20:13:08 +05:30
data = [ ]
2013-08-06 01:53:28 +05:30
#data = [i.strip('"') for i in vs.split()]
2013-07-30 20:13:08 +05:30
RE_VARS = re . compile ( ' \ s*(( \" .+? \" )|([^ \" ] \ S+)) \ s*(.*)$ ' )
while RE_VARS . search ( vs ) :
matches = RE_VARS . search ( vs ) . groups ( )
data . append ( strip_quotes ( matches [ 0 ] ) )
vs = matches [ 3 ]
2013-08-06 01:53:28 +05:30
2013-07-30 20:13:08 +05:30
return data
def is_active_profile ( pname ) :
if aa . get ( pname , False ) :
return True
else :
return False
2014-06-20 13:36:35 +02:00
def store_list_var ( var , list_var , value , var_operation , filename ) :
2013-08-09 16:49:01 +05:30
""" Store(add new variable or add values to variable) the variables encountered in the given list_var """
2013-07-30 20:13:08 +05:30
vlist = separate_vars ( value )
2013-09-22 22:51:30 +05:30
if var_operation == ' = ' :
2013-08-06 01:53:28 +05:30
if not var . get ( list_var , False ) :
var [ list_var ] = set ( vlist )
else :
2013-08-13 00:43:20 +05:30
#print('Ignored: New definition for variable for:',list_var,'=', value, 'operation was:',var_operation,'old value=', var[list_var])
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Redefining existing variable %(variable)s : %(value)s in %(file)s ' ) % { ' variable ' : list_var , ' value ' : value , ' file ' : filename } )
2013-08-11 15:22:07 +05:30
elif var_operation == ' += ' :
2013-08-06 01:53:28 +05:30
if var . get ( list_var , False ) :
var [ list_var ] = set ( var [ list_var ] + vlist )
else :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Values added to a non-existing variable %(variable)s : %(value)s in %(file)s ' ) % { ' variable ' : list_var , ' value ' : value , ' file ' : filename } )
2013-08-11 15:22:07 +05:30
else :
2014-09-14 23:47:00 +05:30
raise AppArmorException ( _ ( ' Unknown variable operation %(operation)s for variable %(variable)s in %(file)s ' ) % { ' operation ' : var_operation , ' variable ' : list_var , ' file ' : filename } )
2013-08-06 01:53:28 +05:30
2013-07-30 20:13:08 +05:30
def quote_if_needed ( data ) :
# quote data if it contains whitespace
if ' ' in data :
data = ' " ' + data + ' " '
return data
def escape ( escape ) :
escape = strip_quotes ( escape )
escape = re . sub ( ' ((?<! \\ )) " ' , r ' \ 1 \\ ' , escape )
if re . search ( ' ( \ s|^$| " ) ' , escape ) :
return ' " %s " ' % escape
return escape
2013-07-31 19:56:33 +05:30
def write_header ( prof_data , depth , name , embedded_hat , write_flags ) :
2015-04-13 18:41:59 -07:00
pre = ' ' * int ( depth * 2 )
2013-07-30 20:13:08 +05:30
data = [ ]
2015-04-13 18:34:33 -07:00
unquoted_name = name
2013-07-30 20:13:08 +05:30
name = quote_if_needed ( name )
2013-09-22 22:51:30 +05:30
2015-04-13 18:34:33 -07:00
attachment = ' '
if prof_data [ ' attachment ' ] :
attachment = ' %s ' % quote_if_needed ( prof_data [ ' attachment ' ] )
2015-04-13 18:41:59 -07:00
comment = ' '
if prof_data [ ' header_comment ' ] :
comment = ' %s ' % prof_data [ ' header_comment ' ]
if ( not embedded_hat and re . search ( ' ^[^/] ' , unquoted_name ) ) or ( embedded_hat and re . search ( ' ^[^^] ' , unquoted_name ) ) or prof_data [ ' attachment ' ] or prof_data [ ' profile_keyword ' ] :
2015-04-13 18:34:33 -07:00
name = ' profile %s %s ' % ( name , attachment )
2013-09-22 22:51:30 +05:30
2015-04-13 18:41:59 -07:00
flags = ' '
2013-07-31 19:56:33 +05:30
if write_flags and prof_data [ ' flags ' ] :
2015-04-13 18:41:59 -07:00
flags = ' flags=( %s ) ' % prof_data [ ' flags ' ]
data . append ( ' %s %s %s { %s ' % ( pre , name , flags , comment ) )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return data
2013-07-31 19:56:33 +05:30
def write_single ( prof_data , depth , allow , name , prefix , tail ) :
2013-07-30 20:13:08 +05:30
pre = ' ' * depth
data = [ ]
2013-07-31 19:56:33 +05:30
ref , allow = set_ref_allow ( prof_data , allow )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if ref . get ( name , False ) :
2013-08-11 23:16:05 +05:30
for key in sorted ( ref [ name ] . keys ( ) ) :
2013-07-30 20:13:08 +05:30
qkey = quote_if_needed ( key )
2014-02-10 22:20:36 -08:00
data . append ( ' %s %s %s %s %s ' % ( pre , allow , prefix , qkey , tail ) )
2013-07-30 20:13:08 +05:30
if ref [ name ] . keys ( ) :
data . append ( ' ' )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return data
2013-07-31 19:56:33 +05:30
def set_allow_str ( allow ) :
if allow == ' deny ' :
return ' deny '
2013-09-23 21:00:36 +05:30
elif allow == ' allow ' :
2013-09-24 00:21:47 +05:30
return ' '
2013-09-23 21:00:36 +05:30
elif allow == ' ' :
return ' '
else :
raise AppArmorException ( _ ( " Invalid allow string: %(allow)s " ) )
2013-07-31 19:56:33 +05:30
def set_ref_allow ( prof_data , allow ) :
2013-07-30 20:13:08 +05:30
if allow :
2013-07-31 19:56:33 +05:30
return prof_data [ allow ] , set_allow_str ( allow )
2013-07-30 20:13:08 +05:30
else :
2013-08-11 23:16:05 +05:30
return prof_data , ' '
2013-07-30 20:13:08 +05:30
2013-07-31 19:56:33 +05:30
def write_pair ( prof_data , depth , allow , name , prefix , sep , tail , fn ) :
2013-07-30 20:13:08 +05:30
pre = ' ' * depth
data = [ ]
2013-07-31 19:56:33 +05:30
ref , allow = set_ref_allow ( prof_data , allow )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if ref . get ( name , False ) :
2013-09-22 15:08:30 +05:30
for key in sorted ( ref [ name ] . keys ( ) ) :
2014-02-10 22:20:36 -08:00
value = fn ( ref [ name ] [ key ] ) # eval('%s(%s)' % (fn, ref[name][key]))
data . append ( ' %s %s %s %s %s %s ' % ( pre , allow , prefix , key , sep , value ) )
2013-07-30 20:13:08 +05:30
if ref [ name ] . keys ( ) :
data . append ( ' ' )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return data
def write_includes ( prof_data , depth ) :
return write_single ( prof_data , depth , ' ' , ' include ' , ' #include < ' , ' > ' )
def write_change_profile ( prof_data , depth ) :
return write_single ( prof_data , depth , ' ' , ' change_profile ' , ' change_profile -> ' , ' , ' )
def write_alias ( prof_data , depth ) :
return write_pair ( prof_data , depth , ' ' , ' alias ' , ' alias ' , ' -> ' , ' , ' , quote_if_needed )
def write_rlimits ( prof_data , depth ) :
return write_pair ( prof_data , depth , ' ' , ' rlimit ' , ' set rlimit ' , ' <= ' , ' , ' , quote_if_needed )
def var_transform ( ref ) :
data = [ ]
for value in ref :
data . append ( quote_if_needed ( value ) )
return ' ' . join ( data )
def write_list_vars ( prof_data , depth ) :
return write_pair ( prof_data , depth , ' ' , ' lvar ' , ' ' , ' = ' , ' ' , var_transform )
def write_cap_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
2013-07-31 19:56:33 +05:30
allowstr = set_allow_str ( allow )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if prof_data [ allow ] . get ( ' capability ' , False ) :
for cap in sorted ( prof_data [ allow ] [ ' capability ' ] . keys ( ) ) :
audit = ' '
if prof_data [ allow ] [ ' capability ' ] [ cap ] . get ( ' audit ' , False ) :
2013-08-21 11:26:09 +05:30
audit = ' audit '
2013-07-30 20:13:08 +05:30
if prof_data [ allow ] [ ' capability ' ] [ cap ] . get ( ' set ' , False ) :
2014-03-20 14:27:24 -05:00
if cap == ALL :
data . append ( ' %s %s %s capability, ' % ( pre , audit , allowstr ) )
else :
data . append ( ' %s %s %s capability %s , ' % ( pre , audit , allowstr , cap ) )
2013-07-30 20:13:08 +05:30
data . append ( ' ' )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return data
def write_capabilities ( prof_data , depth ) :
2013-08-08 21:40:56 +05:30
#data = write_single(prof_data, depth, '', 'set_capability', 'set capability ', ',')
data = write_cap_rules ( prof_data , depth , ' deny ' )
2013-07-30 20:13:08 +05:30
data + = write_cap_rules ( prof_data , depth , ' allow ' )
return data
2013-07-31 19:56:33 +05:30
def write_net_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
allowstr = set_allow_str ( allow )
2013-08-18 14:13:46 +05:30
audit = ' '
2013-07-31 19:56:33 +05:30
if prof_data [ allow ] . get ( ' netdomain ' , False ) :
if prof_data [ allow ] [ ' netdomain ' ] . get ( ' rule ' , False ) == ' all ' :
if prof_data [ allow ] [ ' netdomain ' ] [ ' audit ' ] . get ( ' all ' , False ) :
audit = ' audit '
2014-02-10 22:20:36 -08:00
data . append ( ' %s %s network, ' % ( pre , audit ) )
2013-07-31 19:56:33 +05:30
else :
for fam in sorted ( prof_data [ allow ] [ ' netdomain ' ] [ ' rule ' ] . keys ( ) ) :
2015-04-11 02:21:05 +02:00
audit = ' '
2014-02-10 22:20:36 -08:00
if prof_data [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] is True :
2013-07-31 19:56:33 +05:30
if prof_data [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] :
2015-04-10 01:53:42 +02:00
audit = ' audit '
2015-04-11 02:21:05 +02:00
if fam == ' all ' :
data . append ( ' %s %s %s network, ' % ( pre , audit , allowstr ) )
else :
data . append ( ' %s %s %s network %s , ' % ( pre , audit , allowstr , fam ) )
2013-07-31 19:56:33 +05:30
else :
for typ in sorted ( prof_data [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] . keys ( ) ) :
if prof_data [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] . get ( typ , False ) :
2015-04-10 01:53:42 +02:00
audit = ' audit '
2014-02-10 22:20:36 -08:00
data . append ( ' %s %s %s network %s %s , ' % ( pre , audit , allowstr , fam , typ ) )
2013-07-31 19:56:33 +05:30
if prof_data [ allow ] . get ( ' netdomain ' , False ) :
data . append ( ' ' )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return data
def write_netdomain ( prof_data , depth ) :
data = write_net_rules ( prof_data , depth , ' deny ' )
data + = write_net_rules ( prof_data , depth , ' allow ' )
return data
2014-03-07 09:58:54 -08:00
def write_dbus_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
# no dbus rules, so return
if not prof_data [ allow ] . get ( ' dbus ' , False ) :
return data
for dbus_rule in prof_data [ allow ] [ ' dbus ' ] :
data . append ( ' %s %s ' % ( pre , dbus_rule . serialize ( ) ) )
data . append ( ' ' )
return data
def write_dbus ( prof_data , depth ) :
data = write_dbus_rules ( prof_data , depth , ' deny ' )
2014-03-20 14:19:40 -05:00
data + = write_dbus_rules ( prof_data , depth , ' allow ' )
2014-03-07 09:58:54 -08:00
return data
2014-03-20 14:25:42 -05:00
def write_mount_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
# no mount rules, so return
if not prof_data [ allow ] . get ( ' mount ' , False ) :
return data
for mount_rule in prof_data [ allow ] [ ' mount ' ] :
data . append ( ' %s %s ' % ( pre , mount_rule . serialize ( ) ) )
data . append ( ' ' )
return data
def write_mount ( prof_data , depth ) :
data = write_mount_rules ( prof_data , depth , ' deny ' )
data + = write_mount_rules ( prof_data , depth , ' allow ' )
return data
2014-04-23 15:39:14 -05:00
def write_signal_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
# no signal rules, so return
if not prof_data [ allow ] . get ( ' signal ' , False ) :
return data
for signal_rule in prof_data [ allow ] [ ' signal ' ] :
data . append ( ' %s %s ' % ( pre , signal_rule . serialize ( ) ) )
data . append ( ' ' )
return data
def write_signal ( prof_data , depth ) :
data = write_signal_rules ( prof_data , depth , ' deny ' )
data + = write_signal_rules ( prof_data , depth , ' allow ' )
return data
2014-04-23 15:40:20 -05:00
def write_ptrace_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
# no ptrace rules, so return
if not prof_data [ allow ] . get ( ' ptrace ' , False ) :
return data
for ptrace_rule in prof_data [ allow ] [ ' ptrace ' ] :
data . append ( ' %s %s ' % ( pre , ptrace_rule . serialize ( ) ) )
data . append ( ' ' )
return data
def write_ptrace ( prof_data , depth ) :
data = write_ptrace_rules ( prof_data , depth , ' deny ' )
data + = write_ptrace_rules ( prof_data , depth , ' allow ' )
return data
2014-04-23 15:41:03 -05:00
def write_pivot_root_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
# no pivot_root rules, so return
if not prof_data [ allow ] . get ( ' pivot_root ' , False ) :
return data
for pivot_root_rule in prof_data [ allow ] [ ' pivot_root ' ] :
data . append ( ' %s %s ' % ( pre , pivot_root_rule . serialize ( ) ) )
data . append ( ' ' )
return data
def write_pivot_root ( prof_data , depth ) :
data = write_pivot_root_rules ( prof_data , depth , ' deny ' )
data + = write_pivot_root_rules ( prof_data , depth , ' allow ' )
return data
2013-07-31 19:56:33 +05:30
def write_link_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
allowstr = set_allow_str ( allow )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if prof_data [ allow ] . get ( ' link ' , False ) :
for path in sorted ( prof_data [ allow ] [ ' link ' ] . keys ( ) ) :
to_name = prof_data [ allow ] [ ' link ' ] [ path ] [ ' to ' ]
subset = ' '
2014-02-10 22:17:21 -08:00
if prof_data [ allow ] [ ' link ' ] [ path ] [ ' mode ' ] & apparmor . aamode . AA_LINK_SUBSET :
2013-07-31 19:56:33 +05:30
subset = ' subset '
audit = ' '
if prof_data [ allow ] [ ' link ' ] [ path ] . get ( ' audit ' , False ) :
audit = ' audit '
path = quote_if_needed ( path )
to_name = quote_if_needed ( to_name )
2014-02-10 22:20:36 -08:00
data . append ( ' %s %s %s link %s %s -> %s , ' % ( pre , audit , allowstr , subset , path , to_name ) )
2013-07-31 19:56:33 +05:30
data . append ( ' ' )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return data
def write_links ( prof_data , depth ) :
data = write_link_rules ( prof_data , depth , ' deny ' )
data + = write_link_rules ( prof_data , depth , ' allow ' )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return data
def write_path_rules ( prof_data , depth , allow ) :
pre = ' ' * depth
data = [ ]
allowstr = set_allow_str ( allow )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if prof_data [ allow ] . get ( ' path ' , False ) :
for path in sorted ( prof_data [ allow ] [ ' path ' ] . keys ( ) ) :
2014-04-03 21:58:59 -05:00
filestr = ' '
if prof_data [ allow ] [ ' path ' ] [ path ] . get ( ' file_prefix ' , False ) :
2014-04-23 16:28:17 -05:00
filestr = ' file '
2013-07-31 19:56:33 +05:30
mode = prof_data [ allow ] [ ' path ' ] [ path ] [ ' mode ' ]
audit = prof_data [ allow ] [ ' path ' ] [ path ] [ ' audit ' ]
tail = ' '
if prof_data [ allow ] [ ' path ' ] [ path ] . get ( ' to ' , False ) :
tail = ' -> %s ' % prof_data [ allow ] [ ' path ' ] [ path ] [ ' to ' ]
2014-04-23 16:28:17 -05:00
user , other = split_mode ( mode )
user_audit , other_audit = split_mode ( audit )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
while user or other :
ownerstr = ' '
tmpmode = 0
tmpaudit = False
2013-08-11 18:30:01 +05:30
if user - other :
2013-09-22 22:51:30 +05:30
# if no other mode set
2013-09-22 15:01:34 +05:30
ownerstr = ' owner '
2013-08-11 18:30:01 +05:30
tmpmode = user - other
2013-07-31 19:56:33 +05:30
tmpaudit = user_audit
2013-08-11 18:30:01 +05:30
user = user - tmpmode
2013-07-31 19:56:33 +05:30
else :
2013-08-11 18:30:01 +05:30
if user_audit - other_audit & user :
2013-07-31 19:56:33 +05:30
ownerstr = ' owner '
2013-08-11 18:30:01 +05:30
tmpaudit = user_audit - other_audit & user
2013-07-31 19:56:33 +05:30
tmpmode = user & tmpaudit
2013-08-11 18:30:01 +05:30
user = user - tmpmode
2013-07-31 19:56:33 +05:30
else :
ownerstr = ' '
tmpmode = user | other
tmpaudit = user_audit | other_audit
2013-08-11 18:30:01 +05:30
user = user - tmpmode
other = other - tmpmode
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
if path == ALL :
path = ' '
2013-07-31 19:56:33 +05:30
if tmpmode & tmpaudit :
modestr = mode_to_str ( tmpmode & tmpaudit )
2014-04-23 16:28:17 -05:00
if modestr :
modestr = ' ' + modestr
2013-07-31 19:56:33 +05:30
path = quote_if_needed ( path )
2014-04-23 16:28:17 -05:00
if filestr and path :
filestr + = ' '
data . append ( ' %s audit %s %s %s %s %s %s , ' % ( pre , allowstr , ownerstr , filestr , path , modestr , tail ) )
2013-08-11 18:30:01 +05:30
tmpmode = tmpmode - tmpaudit
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if tmpmode :
modestr = mode_to_str ( tmpmode )
2014-04-23 16:28:17 -05:00
if modestr :
modestr = ' ' + modestr
2013-07-31 19:56:33 +05:30
path = quote_if_needed ( path )
2014-04-23 16:28:17 -05:00
if filestr and path :
filestr + = ' '
data . append ( ' %s %s %s %s %s %s %s , ' % ( pre , allowstr , ownerstr , filestr , path , modestr , tail ) )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
data . append ( ' ' )
return data
def write_paths ( prof_data , depth ) :
data = write_path_rules ( prof_data , depth , ' deny ' )
data + = write_path_rules ( prof_data , depth , ' allow ' )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return data
def write_rules ( prof_data , depth ) :
data = write_alias ( prof_data , depth )
data + = write_list_vars ( prof_data , depth )
data + = write_includes ( prof_data , depth )
data + = write_rlimits ( prof_data , depth )
data + = write_capabilities ( prof_data , depth )
data + = write_netdomain ( prof_data , depth )
2014-03-07 09:58:54 -08:00
data + = write_dbus ( prof_data , depth )
2014-03-20 14:25:42 -05:00
data + = write_mount ( prof_data , depth )
2014-04-23 15:39:14 -05:00
data + = write_signal ( prof_data , depth )
2014-04-23 15:40:20 -05:00
data + = write_ptrace ( prof_data , depth )
2014-04-23 15:41:03 -05:00
data + = write_pivot_root ( prof_data , depth )
2013-07-31 19:56:33 +05:30
data + = write_links ( prof_data , depth )
data + = write_paths ( prof_data , depth )
data + = write_change_profile ( prof_data , depth )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return data
def write_piece ( profile_data , depth , name , nhat , write_flags ) :
pre = ' ' * depth
data = [ ]
wname = None
inhat = False
if name == nhat :
wname = name
else :
wname = name + ' // ' + nhat
name = nhat
inhat = True
data + = write_header ( profile_data [ name ] , depth , wname , False , write_flags )
2014-02-10 22:20:36 -08:00
data + = write_rules ( profile_data [ name ] , depth + 1 )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
pre2 = ' ' * ( depth + 1 )
2013-07-31 19:56:33 +05:30
# External hat declarations
2013-08-13 00:43:20 +05:30
for hat in list ( filter ( lambda x : x != name , sorted ( profile_data . keys ( ) ) ) ) :
2013-07-31 19:56:33 +05:30
if profile_data [ hat ] . get ( ' declared ' , False ) :
2014-02-10 22:20:36 -08:00
data . append ( ' %s ^ %s , ' % ( pre2 , hat ) )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if not inhat :
# Embedded hats
2013-08-13 00:43:20 +05:30
for hat in list ( filter ( lambda x : x != name , sorted ( profile_data . keys ( ) ) ) ) :
2013-07-31 19:56:33 +05:30
if not profile_data [ hat ] [ ' external ' ] and not profile_data [ hat ] [ ' declared ' ] :
data . append ( ' ' )
if profile_data [ hat ] [ ' profile ' ] :
2014-02-10 22:20:36 -08:00
data + = list ( map ( str , write_header ( profile_data [ hat ] , depth + 1 , hat , True , write_flags ) ) )
2013-07-31 19:56:33 +05:30
else :
2014-02-10 22:20:36 -08:00
data + = list ( map ( str , write_header ( profile_data [ hat ] , depth + 1 , ' ^ ' + hat , True , write_flags ) ) )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
data + = list ( map ( str , write_rules ( profile_data [ hat ] , depth + 2 ) ) )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
data . append ( ' %s } ' % pre2 )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
data . append ( ' %s } ' % pre )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
# External hats
2013-08-13 00:43:20 +05:30
for hat in list ( filter ( lambda x : x != name , sorted ( profile_data . keys ( ) ) ) ) :
2013-07-31 19:56:33 +05:30
if name == nhat and profile_data [ hat ] . get ( ' external ' , False ) :
data . append ( ' ' )
2014-02-10 22:20:36 -08:00
data + = list ( map ( lambda x : ' %s ' % x , write_piece ( profile_data , depth - 1 , name , nhat , write_flags ) ) )
2013-07-31 19:56:33 +05:30
data . append ( ' } ' )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return data
def serialize_profile ( profile_data , name , options ) :
string = ' '
include_metadata = False
include_flags = True
2014-02-10 22:20:36 -08:00
data = [ ]
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
if options : # and type(options) == dict:
2013-07-31 19:56:33 +05:30
if options . get ( ' METADATA ' , False ) :
include_metadata = True
if options . get ( ' NO_FLAGS ' , False ) :
include_flags = False
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if include_metadata :
2014-02-10 22:20:36 -08:00
string = ' # Last Modified: %s \n ' % time . asctime ( )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
if ( profile_data [ name ] . get ( ' repo ' , False ) and
profile_data [ name ] [ ' repo ' ] [ ' url ' ] and
profile_data [ name ] [ ' repo ' ] [ ' user ' ] and
profile_data [ name ] [ ' repo ' ] [ ' id ' ] ) :
2013-07-31 19:56:33 +05:30
repo = profile_data [ name ] [ ' repo ' ]
2014-02-10 22:20:36 -08:00
string + = ' # REPOSITORY: %s %s %s \n ' % ( repo [ ' url ' ] , repo [ ' user ' ] , repo [ ' id ' ] )
2013-07-31 19:56:33 +05:30
elif profile_data [ name ] [ ' repo ' ] [ ' neversubmit ' ] :
string + = ' # REPOSITORY: NEVERSUBMIT \n '
2013-09-22 22:51:30 +05:30
2013-09-22 15:01:34 +05:30
# if profile_data[name].get('initial_comment', False):
# comment = profile_data[name]['initial_comment']
# comment.replace('\\n', '\n')
# string += comment + '\n'
2013-09-22 22:51:30 +05:30
2013-08-01 21:57:27 +05:30
prof_filename = get_profile_filename ( name )
if filelist . get ( prof_filename , False ) :
data + = write_alias ( filelist [ prof_filename ] , 0 )
data + = write_list_vars ( filelist [ prof_filename ] , 0 )
data + = write_includes ( filelist [ prof_filename ] , 0 )
2013-09-22 15:01:34 +05:30
#Here should be all the profiles from the files added write after global/common stuff
for prof in sorted ( filelist [ prof_filename ] [ ' profiles ' ] . keys ( ) ) :
if prof != name :
if original_aa [ prof ] [ prof ] . get ( ' initial_comment ' , False ) :
2014-03-16 20:36:42 +05:30
comment = original_aa [ prof ] [ prof ] [ ' initial_comment ' ]
2013-09-22 15:01:34 +05:30
comment . replace ( ' \\ n ' , ' \n ' )
data + = [ comment + ' \n ' ]
data + = write_piece ( original_aa [ prof ] , 0 , prof , prof , include_flags )
else :
if profile_data [ name ] . get ( ' initial_comment ' , False ) :
comment = profile_data [ name ] [ ' initial_comment ' ]
comment . replace ( ' \\ n ' , ' \n ' )
data + = [ comment + ' \n ' ]
data + = write_piece ( profile_data , 0 , name , name , include_flags )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
string + = ' \n ' . join ( data )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
return string + ' \n '
2013-07-31 19:56:33 +05:30
2015-03-10 19:09:16 +01:00
def serialize_parse_profile_start ( line , file , lineno , profile , hat , prof_data_profile , prof_data_external , correct ) :
2015-04-13 18:24:20 -07:00
matches = parse_profile_start_line ( line , file )
if profile and profile == hat and matches [ ' profile_keyword ' ] :
hat = matches [ ' profile ' ]
2015-03-10 19:09:16 +01:00
in_contained_hat = True
if prof_data_profile :
pass
else :
2015-04-13 18:24:20 -07:00
profile = matches [ ' profile ' ]
2015-03-10 19:09:16 +01:00
if len ( profile . split ( ' // ' ) ) > = 2 :
profile , hat = profile . split ( ' // ' ) [ : 2 ]
else :
hat = None
in_contained_hat = False
if hat and not prof_data_external :
correct = False
else :
hat = profile
2015-04-13 18:36:42 -07:00
attachment = matches [ ' attachment ' ]
2015-04-13 18:24:20 -07:00
flags = matches [ ' flags ' ]
2015-03-10 19:09:16 +01:00
2015-04-13 18:36:42 -07:00
return ( profile , hat , attachment , flags , in_contained_hat , correct )
2015-03-10 19:09:16 +01:00
2013-08-18 14:13:46 +05:30
def serialize_profile_from_old_profile ( profile_data , name , options ) :
data = [ ]
string = ' '
include_metadata = False
include_flags = True
prof_filename = get_profile_filename ( name )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
write_filelist = deepcopy ( filelist [ prof_filename ] )
write_prof_data = deepcopy ( profile_data )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
if options : # and type(options) == dict:
2013-08-18 14:13:46 +05:30
if options . get ( ' METADATA ' , False ) :
include_metadata = True
if options . get ( ' NO_FLAGS ' , False ) :
include_flags = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if include_metadata :
2014-02-10 22:20:36 -08:00
string = ' # Last Modified: %s \n ' % time . asctime ( )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
if ( profile_data [ name ] . get ( ' repo ' , False ) and
profile_data [ name ] [ ' repo ' ] [ ' url ' ] and
profile_data [ name ] [ ' repo ' ] [ ' user ' ] and
profile_data [ name ] [ ' repo ' ] [ ' id ' ] ) :
2013-08-18 14:13:46 +05:30
repo = profile_data [ name ] [ ' repo ' ]
2014-02-10 22:20:36 -08:00
string + = ' # REPOSITORY: %s %s %s \n ' % ( repo [ ' url ' ] , repo [ ' user ' ] , repo [ ' id ' ] )
2013-08-18 14:13:46 +05:30
elif profile_data [ name ] [ ' repo ' ] [ ' neversubmit ' ] :
string + = ' # REPOSITORY: NEVERSUBMIT \n '
if not os . path . isfile ( prof_filename ) :
2013-09-21 01:08:34 +05:30
raise AppArmorException ( _ ( " Can ' t find existing profile to modify " ) )
2014-02-10 22:20:36 -08:00
2014-02-13 10:52:00 -08:00
# profiles_list = filelist[prof_filename].keys() # XXX
2014-02-10 22:20:36 -08:00
2013-08-18 14:13:46 +05:30
with open_file_read ( prof_filename ) as f_in :
profile = None
hat = None
2013-08-19 12:37:47 +05:30
write_methods = { ' alias ' : write_alias ,
' lvar ' : write_list_vars ,
' include ' : write_includes ,
' rlimit ' : write_rlimits ,
' capability ' : write_capabilities ,
' netdomain ' : write_netdomain ,
2014-03-07 09:58:54 -08:00
' dbus ' : write_dbus ,
2014-03-20 14:25:42 -05:00
' mount ' : write_mount ,
2014-04-23 15:39:14 -05:00
' signal ' : write_signal ,
2014-04-23 15:40:20 -05:00
' ptrace ' : write_ptrace ,
2014-04-23 15:41:03 -05:00
' pivot_root ' : write_pivot_root ,
2013-08-19 12:37:47 +05:30
' link ' : write_links ,
' path ' : write_paths ,
' change_profile ' : write_change_profile ,
}
2014-11-15 12:51:24 +01:00
default_write_order = [ ' alias ' ,
' lvar ' ,
' include ' ,
' rlimit ' ,
' capability ' ,
' netdomain ' ,
' dbus ' ,
' mount ' ,
' signal ' ,
' ptrace ' ,
' pivot_root ' ,
' link ' ,
' path ' ,
' change_profile ' ,
]
2014-02-13 10:52:00 -08:00
# prof_correct = True # XXX correct?
2014-02-10 22:20:36 -08:00
segments = { ' alias ' : False ,
2013-08-19 12:37:47 +05:30
' lvar ' : False ,
' include ' : False ,
' rlimit ' : False ,
' capability ' : False ,
' netdomain ' : False ,
2014-03-07 09:58:54 -08:00
' dbus ' : False ,
2014-11-15 12:51:24 +01:00
' mount ' : True , # not handled otherwise yet
' signal ' : True , # not handled otherwise yet
' ptrace ' : True , # not handled otherwise yet
' pivot_root ' : True , # not handled otherwise yet
2013-08-19 12:37:47 +05:30
' link ' : False ,
' path ' : False ,
' change_profile ' : False ,
2014-11-15 12:51:24 +01:00
' include_local_started ' : False , # unused
2014-02-10 22:20:36 -08:00
}
2014-11-26 14:32:25 -08:00
def write_prior_segments ( prof_data , segments , line ) :
data = [ ]
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
data + = write_methods [ segs ] ( prof_data , int ( depth / 2 ) )
segments [ segs ] = False
if prof_data [ ' allow ' ] . get ( segs , False ) :
prof_data [ ' allow ' ] . pop ( segs )
if prof_data [ ' deny ' ] . get ( segs , False ) :
prof_data [ ' deny ' ] . pop ( segs )
return data
2013-08-19 12:37:47 +05:30
#data.append('reading prof')
2013-08-18 14:13:46 +05:30
for line in f_in :
correct = True
line = line . rstrip ( ' \n ' )
2013-08-19 12:37:47 +05:30
#data.append(' ')#data.append('read: '+line)
2013-08-18 14:13:46 +05:30
if RE_PROFILE_START . search ( line ) :
2013-09-22 22:51:30 +05:30
2015-04-13 18:36:42 -07:00
( profile , hat , attachment , flags , in_contained_hat , correct ) = serialize_parse_profile_start (
2015-03-10 19:09:16 +01:00
line , prof_filename , None , profile , hat , write_prof_data [ profile ] [ hat ] [ ' profile ' ] , write_prof_data [ profile ] [ hat ] [ ' external ' ] , correct )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ ' name ' ] == profile :
correct = False
2014-02-10 22:20:36 -08:00
if not write_filelist [ ' profiles ' ] [ profile ] [ hat ] is True :
2013-08-18 14:13:46 +05:30
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ ' flags ' ] == flags :
correct = False
#Write the profile start
if correct :
2013-08-19 12:37:47 +05:30
if write_filelist :
data + = write_alias ( write_filelist , 0 )
data + = write_list_vars ( write_filelist , 0 )
data + = write_includes ( write_filelist , 0 )
2013-08-18 14:13:46 +05:30
data . append ( line )
else :
2013-08-19 12:37:47 +05:30
if write_prof_data [ hat ] [ ' name ' ] == profile :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_header ( write_prof_data [ name ] , int ( depth / 2 ) , name , False , include_flags )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_END . search ( line ) :
# DUMP REMAINDER OF PROFILE
if profile :
2014-11-15 12:51:24 +01:00
depth = int ( len ( line ) - len ( line . lstrip ( ) ) / 2 ) + 1
2013-09-22 22:51:30 +05:30
2014-11-15 12:51:24 +01:00
# first write sections that were modified (and remove them from write_prof_data)
#for segs in write_methods.keys():
for segs in default_write_order :
if segments [ segs ] :
data + = write_methods [ segs ] ( write_prof_data [ name ] , depth )
2013-08-19 12:37:47 +05:30
segments [ segs ] = False
2014-02-10 22:20:36 -08:00
if write_prof_data [ name ] [ ' allow ' ] . get ( segs , False ) :
write_prof_data [ name ] [ ' allow ' ] . pop ( segs )
if write_prof_data [ name ] [ ' deny ' ] . get ( segs , False ) :
write_prof_data [ name ] [ ' deny ' ] . pop ( segs )
2013-08-19 12:37:47 +05:30
2014-11-15 12:51:24 +01:00
# then write everything else
for segs in default_write_order :
data + = write_methods [ segs ] ( write_prof_data [ name ] , depth )
2013-09-22 22:51:30 +05:30
2013-08-19 12:37:47 +05:30
write_prof_data . pop ( name )
2013-09-22 22:51:30 +05:30
2013-08-19 12:37:47 +05:30
#Append local includes
2013-08-18 14:13:46 +05:30
data . append ( line )
2013-09-22 22:51:30 +05:30
2013-08-19 12:37:47 +05:30
if not in_contained_hat :
# Embedded hats
2014-02-10 22:20:36 -08:00
depth = int ( ( len ( line ) - len ( line . lstrip ( ) ) ) / 2 )
pre2 = ' ' * ( depth + 1 )
2013-08-19 12:37:47 +05:30
for hat in list ( filter ( lambda x : x != name , sorted ( profile_data . keys ( ) ) ) ) :
if not profile_data [ hat ] [ ' external ' ] and not profile_data [ hat ] [ ' declared ' ] :
data . append ( ' ' )
if profile_data [ hat ] [ ' profile ' ] :
2014-02-10 22:20:36 -08:00
data + = list ( map ( str , write_header ( profile_data [ hat ] , depth + 1 , hat , True , include_flags ) ) )
2013-08-19 12:37:47 +05:30
else :
2014-02-10 22:20:36 -08:00
data + = list ( map ( str , write_header ( profile_data [ hat ] , depth + 1 , ' ^ ' + hat , True , include_flags ) ) )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
data + = list ( map ( str , write_rules ( profile_data [ hat ] , depth + 2 ) ) )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
data . append ( ' %s } ' % pre2 )
2013-09-22 22:51:30 +05:30
2013-08-19 12:37:47 +05:30
# External hats
for hat in list ( filter ( lambda x : x != name , sorted ( profile_data . keys ( ) ) ) ) :
if profile_data [ hat ] . get ( ' external ' , False ) :
data . append ( ' ' )
2014-02-10 22:20:36 -08:00
data + = list ( map ( lambda x : ' %s ' % x , write_piece ( profile_data , depth - 1 , name , name , include_flags ) ) )
2013-08-19 12:37:47 +05:30
data . append ( ' } ' )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if in_contained_hat :
#Hat processed, remove it
hat = profile
in_contained_hat = False
else :
profile = None
elif RE_PROFILE_CAP . search ( line ) :
matches = RE_PROFILE_CAP . search ( line ) . groups ( )
audit = False
if matches [ 0 ] :
audit = matches [ 0 ]
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
2013-09-22 22:51:30 +05:30
2014-03-20 14:27:24 -05:00
capability = ALL
if matches [ 2 ] :
capability = matches [ 2 ] . strip ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ allow ] [ ' capability ' ] [ capability ] . get ( ' set ' , False ) :
correct = False
if not write_prof_data [ hat ] [ allow ] [ ' capability ' ] [ capability ] . get ( audit , False ) == audit :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' capability ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' capability ' ] = True
2013-08-18 14:13:46 +05:30
write_prof_data [ hat ] [ allow ] [ ' capability ' ] . pop ( capability )
data . append ( line )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
#write_prof_data[hat][allow]['capability'][capability].pop(audit)
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
#Remove this line
else :
# To-Do
pass
elif RE_PROFILE_LINK . search ( line ) :
matches = RE_PROFILE_LINK . search ( line ) . groups ( )
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
subset = matches [ 3 ]
link = strip_quotes ( matches [ 6 ] )
value = strip_quotes ( matches [ 7 ] )
if not write_prof_data [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' to ' ] == value :
correct = False
2014-02-10 22:17:21 -08:00
if not write_prof_data [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' mode ' ] & apparmor . aamode . AA_MAY_LINK :
2013-08-18 14:13:46 +05:30
correct = False
2014-02-10 22:17:21 -08:00
if subset and not write_prof_data [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' mode ' ] & apparmor . aamode . AA_LINK_SUBSET :
2013-08-18 14:13:46 +05:30
correct = False
2014-02-10 22:17:21 -08:00
if audit and not write_prof_data [ hat ] [ allow ] [ ' link ' ] [ link ] [ ' audit ' ] & apparmor . aamode . AA_LINK_SUBSET :
2013-08-18 14:13:46 +05:30
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' link ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' link ' ] = True
2013-08-18 14:13:46 +05:30
write_prof_data [ hat ] [ allow ] [ ' link ' ] . pop ( link )
data . append ( line )
else :
# To-Do
pass
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_CHANGE_PROFILE . search ( line ) :
matches = RE_PROFILE_CHANGE_PROFILE . search ( line ) . groups ( )
cp = strip_quotes ( matches [ 0 ] )
2013-09-22 22:51:30 +05:30
2014-11-29 13:40:10 +01:00
if not write_prof_data [ hat ] [ ' change_profile ' ] [ cp ] is True :
2013-08-18 14:13:46 +05:30
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' change_profile ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' change_profile ' ] = True
write_prof_data [ hat ] [ ' change_profile ' ] . pop ( cp )
2013-08-18 14:13:46 +05:30
data . append ( line )
else :
#To-Do
pass
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_ALIAS . search ( line ) :
matches = RE_PROFILE_ALIAS . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
from_name = strip_quotes ( matches [ 0 ] )
to_name = strip_quotes ( matches [ 1 ] )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if profile :
if not write_prof_data [ hat ] [ ' alias ' ] [ from_name ] == to_name :
correct = False
else :
if not write_filelist [ ' alias ' ] [ from_name ] == to_name :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' alias ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' alias ' ] = True
if profile :
write_prof_data [ hat ] [ ' alias ' ] . pop ( from_name )
else :
write_filelist [ ' alias ' ] . pop ( from_name )
2013-08-18 14:13:46 +05:30
data . append ( line )
else :
#To-Do
pass
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_RLIMIT . search ( line ) :
matches = RE_PROFILE_RLIMIT . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
from_name = matches [ 0 ]
to_name = matches [ 2 ]
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ ' rlimit ' ] [ from_name ] == to_name :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' rlimit ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' rlimit ' ] = True
write_prof_data [ hat ] [ ' rlimit ' ] . pop ( from_name )
2013-08-18 14:13:46 +05:30
data . append ( line )
else :
#To-Do
pass
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_BOOLEAN . search ( line ) :
matches = RE_PROFILE_BOOLEAN . search ( line ) . groups ( )
bool_var = matches [ 0 ]
value = matches [ 1 ]
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ ' lvar ' ] [ bool_var ] == value :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' lvar ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' lvar ' ] = True
write_prof_data [ hat ] [ ' lvar ' ] . pop ( bool_var )
2013-08-18 14:13:46 +05:30
data . append ( line )
else :
#To-Do
pass
elif RE_PROFILE_VARIABLE . search ( line ) :
matches = RE_PROFILE_VARIABLE . search ( line ) . groups ( )
list_var = strip_quotes ( matches [ 0 ] )
var_operation = matches [ 1 ]
value = strip_quotes ( matches [ 2 ] )
var_set = hasher ( )
if profile :
2014-06-20 13:36:35 +02:00
store_list_var ( var_set , list_var , value , var_operation , prof_filename )
2013-08-18 14:13:46 +05:30
if not var_set [ list_var ] == write_prof_data [ ' lvar ' ] . get ( list_var , False ) :
correct = False
else :
2014-06-20 13:36:35 +02:00
store_list_var ( var_set , list_var , value , var_operation , prof_filename )
2013-08-18 14:13:46 +05:30
if not var_set [ list_var ] == write_filelist [ ' lvar ' ] . get ( list_var , False ) :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
if correct :
2013-08-19 12:37:47 +05:30
if not segments [ ' lvar ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' lvar ' ] = True
if profile :
write_prof_data [ hat ] [ ' lvar ' ] . pop ( list_var )
else :
write_filelist [ ' lvar ' ] . pop ( list_var )
2013-08-18 14:13:46 +05:30
data . append ( line )
else :
#To-Do
pass
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
elif RE_PROFILE_BARE_FILE_ENTRY . search ( line ) :
matches = RE_PROFILE_BARE_FILE_ENTRY . search ( line ) . groups ( )
2013-08-18 14:13:46 +05:30
allow = ' allow '
2014-04-23 16:28:17 -05:00
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
2013-08-18 14:13:46 +05:30
allow = ' deny '
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
mode = apparmor . aamode . AA_BARE_FILE_MODE
if not matches [ 2 ] :
mode | = AA_OTHER ( apparmor . aamode . AA_BARE_FILE_MODE )
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
audit = set ( )
if matches [ 0 ] :
audit = mode
2013-09-22 22:51:30 +05:30
2014-04-23 16:28:17 -05:00
path_rule = write_prof_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ ALL ]
if path_rule . get ( ' mode ' , set ( ) ) & mode and \
( not audit or path_rule . get ( ' audit ' , set ( ) ) & audit ) and \
path_rule . get ( ' file_prefix ' , set ( ) ) :
2013-08-19 12:37:47 +05:30
if not segments [ ' path ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' path ' ] = True
2014-04-23 16:28:17 -05:00
write_prof_data [ hat ] [ allow ] [ ' path ' ] . pop ( ALL )
2014-04-03 21:58:59 -05:00
data . append ( line )
2014-04-23 16:28:17 -05:00
elif RE_PROFILE_PATH_ENTRY . search ( line ) :
matches = RE_PROFILE_PATH_ENTRY . search ( line ) . groups ( )
2014-04-03 21:58:59 -05:00
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . split ( ) == ' deny ' :
allow = ' deny '
user = False
if matches [ 2 ] :
user = True
2014-10-11 23:30:46 +02:00
path = strip_quotes ( matches [ 4 ] . strip ( ) )
2014-04-23 16:28:17 -05:00
mode = matches [ 5 ]
2015-04-11 02:16:08 +02:00
nt_name = matches [ 7 ]
2014-04-23 16:28:17 -05:00
if nt_name :
nt_name = nt_name . strip ( )
2014-04-03 21:58:59 -05:00
tmpmode = set ( )
2014-04-23 16:28:17 -05:00
if user :
tmpmode = str_to_mode ( ' %s :: ' % mode )
else :
tmpmode = str_to_mode ( mode )
2014-04-03 21:58:59 -05:00
if not write_prof_data [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' mode ' , set ( ) ) & tmpmode :
2014-04-23 16:28:17 -05:00
correct = False
2014-04-03 21:58:59 -05:00
if nt_name and not write_prof_data [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' to ' , False ) == nt_name :
correct = False
if audit and not write_prof_data [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' audit ' , set ( ) ) & tmpmode :
2014-04-23 16:28:17 -05:00
correct = False
2014-04-03 21:58:59 -05:00
if correct :
if not segments [ ' path ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2014-04-03 21:58:59 -05:00
segments [ ' path ' ] = True
2013-08-18 14:13:46 +05:30
write_prof_data [ hat ] [ allow ] [ ' path ' ] . pop ( path )
data . append ( line )
else :
#To-Do
pass
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif re_match_include ( line ) :
include_name = re_match_include ( line )
if profile :
if write_prof_data [ hat ] [ ' include ' ] . get ( include_name , False ) :
2013-08-19 12:37:47 +05:30
if not segments [ ' include ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2014-11-26 14:28:21 -08:00
segments [ ' include ' ] = True
2013-08-18 14:13:46 +05:30
write_prof_data [ hat ] [ ' include ' ] . pop ( include_name )
data . append ( line )
else :
if write_filelist [ ' include ' ] . get ( include_name , False ) :
write_filelist [ ' include ' ] . pop ( include_name )
data . append ( line )
elif RE_PROFILE_NETWORK . search ( line ) :
matches = RE_PROFILE_NETWORK . search ( line ) . groups ( )
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . strip ( ) == ' deny ' :
allow = ' deny '
network = matches [ 2 ]
if RE_NETWORK_FAMILY_TYPE . search ( network ) :
nmatch = RE_NETWORK_FAMILY_TYPE . search ( network ) . groups ( )
fam , typ = nmatch [ : 2 ]
if write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] [ typ ] and write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] [ typ ] == audit :
write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] . pop ( typ )
write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] . pop ( typ )
data . append ( line )
2013-08-19 12:37:47 +05:30
else :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
elif RE_NETWORK_FAMILY . search ( network ) :
fam = RE_NETWORK_FAMILY . search ( network ) . groups ( ) [ 0 ]
if write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] and write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] == audit :
write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] . pop ( fam )
write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] . pop ( fam )
data . append ( line )
2013-08-19 12:37:47 +05:30
else :
correct = False
2013-08-18 14:13:46 +05:30
else :
if write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ ' all ' ] and write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ ' all ' ] == audit :
write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' rule ' ] . pop ( ' all ' )
write_prof_data [ hat ] [ allow ] [ ' netdomain ' ] [ ' audit ' ] . pop ( ' all ' )
data . append ( line )
2013-08-19 12:37:47 +05:30
else :
correct = False
2013-09-22 22:51:30 +05:30
2013-08-19 12:37:47 +05:30
if correct :
if not segments [ ' netdomain ' ] and True in segments . values ( ) :
2014-11-26 14:32:25 -08:00
data + = write_prior_segments ( write_prof_data [ name ] , segments , line )
2013-08-19 12:37:47 +05:30
segments [ ' netdomain ' ] = True
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_CHANGE_HAT . search ( line ) :
matches = RE_PROFILE_CHANGE_HAT . search ( line ) . groups ( )
hat = matches [ 0 ]
2014-02-10 22:20:36 -08:00
hat = strip_quotes ( hat )
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ ' declared ' ] :
correct = False
if correct :
data . append ( line )
else :
#To-Do
pass
elif RE_PROFILE_HAT_DEF . search ( line ) :
2014-10-16 22:03:42 +02:00
matches = RE_PROFILE_HAT_DEF . search ( line )
2013-08-18 14:13:46 +05:30
in_contained_hat = True
2014-10-16 22:03:42 +02:00
hat = matches . group ( ' hat ' )
2013-08-18 14:13:46 +05:30
hat = strip_quotes ( hat )
2014-10-16 22:03:42 +02:00
flags = matches . group ( ' flags ' )
2013-08-18 14:13:46 +05:30
if not write_prof_data [ hat ] [ ' flags ' ] == flags :
correct = False
2014-02-10 22:20:36 -08:00
if not write_prof_data [ hat ] [ ' declared ' ] is False :
2013-08-18 14:13:46 +05:30
correct = False
if not write_filelist [ ' profile ' ] [ profile ] [ hat ] :
correct = False
if correct :
data . append ( line )
else :
#To-Do
pass
else :
if correct :
data . append ( line )
else :
#To-Do
pass
2013-08-19 12:37:47 +05:30
# data.append('prof done')
# if write_filelist:
# data += write_alias(write_filelist, 0)
# data += write_list_vars(write_filelist, 0)
# data += write_includes(write_filelist, 0)
# data.append('from filelist over')
# data += write_piece(write_prof_data, 0, name, name, include_flags)
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
string + = ' \n ' . join ( data )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
return string + ' \n '
2013-08-18 14:13:46 +05:30
2013-07-31 19:56:33 +05:30
def write_profile_ui_feedback ( profile ) :
2014-02-10 22:20:36 -08:00
aaui . UI_Info ( _ ( ' Writing updated profile for %s . ' ) % profile )
2013-07-31 19:56:33 +05:30
write_profile ( profile )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
def write_profile ( profile ) :
2013-08-01 21:57:27 +05:30
prof_filename = None
2013-07-31 19:56:33 +05:30
if aa [ profile ] [ profile ] . get ( ' filename ' , False ) :
2013-08-01 21:57:27 +05:30
prof_filename = aa [ profile ] [ profile ] [ ' filename ' ]
2013-07-31 19:56:33 +05:30
else :
2013-08-01 21:57:27 +05:30
prof_filename = get_profile_filename ( profile )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
newprof = tempfile . NamedTemporaryFile ( ' w ' , suffix = ' ~ ' , delete = False , dir = profile_dir )
2013-08-01 21:57:27 +05:30
if os . path . exists ( prof_filename ) :
shutil . copymode ( prof_filename , newprof . name )
2013-07-31 19:56:33 +05:30
else :
#permission_600 = stat.S_IRUSR | stat.S_IWUSR # Owner read and write
#os.chmod(newprof.name, permission_600)
pass
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
serialize_options = { }
serialize_options [ ' METADATA ' ] = True
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
profile_string = serialize_profile ( aa [ profile ] , profile , serialize_options )
newprof . write ( profile_string )
newprof . close ( )
2013-09-22 22:51:30 +05:30
2013-08-01 21:57:27 +05:30
os . rename ( newprof . name , prof_filename )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
changed . pop ( profile )
original_aa [ profile ] = deepcopy ( aa [ profile ] )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
def matchliteral ( aa_regexp , literal ) :
2014-02-10 22:20:36 -08:00
p_regexp = ' ^ ' + convert_regexp ( aa_regexp ) + ' $ '
2013-07-31 19:56:33 +05:30
match = False
try :
match = re . search ( p_regexp , literal )
except :
return None
return match
def profile_known_exec ( profile , typ , exec_target ) :
if typ == ' exec ' :
cm = None
am = None
m = [ ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
cm , am , m = rematchfrag ( profile , ' deny ' , exec_target )
2014-02-10 22:17:21 -08:00
if cm & apparmor . aamode . AA_MAY_EXEC :
2013-07-31 19:56:33 +05:30
return - 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
cm , am , m = match_prof_incs_to_path ( profile , ' deny ' , exec_target )
2014-02-10 22:17:21 -08:00
if cm & apparmor . aamode . AA_MAY_EXEC :
2013-07-31 19:56:33 +05:30
return - 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
cm , am , m = rematchfrag ( profile , ' allow ' , exec_target )
2014-02-10 22:17:21 -08:00
if cm & apparmor . aamode . AA_MAY_EXEC :
2013-07-31 19:56:33 +05:30
return 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
cm , am , m = match_prof_incs_to_path ( profile , ' allow ' , exec_target )
2014-02-10 22:17:21 -08:00
if cm & apparmor . aamode . AA_MAY_EXEC :
2013-07-31 19:56:33 +05:30
return 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return 0
def profile_known_capability ( profile , capname ) :
if profile [ ' deny ' ] [ ' capability ' ] [ capname ] . get ( ' set ' , False ) :
return - 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if profile [ ' allow ' ] [ ' capability ' ] [ capname ] . get ( ' set ' , False ) :
return 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
for incname in profile [ ' include ' ] . keys ( ) :
if include [ incname ] [ incname ] [ ' deny ' ] [ ' capability ' ] [ capname ] . get ( ' set ' , False ) :
return - 1
if include [ incname ] [ incname ] [ ' allow ' ] [ ' capability ' ] [ capname ] . get ( ' set ' , False ) :
return 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return 0
def profile_known_network ( profile , family , sock_type ) :
if netrules_access_check ( profile [ ' deny ' ] [ ' netdomain ' ] , family , sock_type ) :
return - 1
if netrules_access_check ( profile [ ' allow ' ] [ ' netdomain ' ] , family , sock_type ) :
return 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
for incname in profile [ ' include ' ] . keys ( ) :
if netrules_access_check ( include [ incname ] [ incname ] [ ' deny ' ] [ ' netdomain ' ] , family , sock_type ) :
return - 1
if netrules_access_check ( include [ incname ] [ incname ] [ ' allow ' ] [ ' netdomain ' ] , family , sock_type ) :
return 1
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return 0
def netrules_access_check ( netrules , family , sock_type ) :
if not netrules :
return 0
all_net = False
all_net_family = False
net_family_sock = False
if netrules [ ' rule ' ] . get ( ' all ' , False ) :
all_net = True
2014-02-10 22:20:36 -08:00
if netrules [ ' rule ' ] . get ( family , False ) is True :
2013-07-31 19:56:33 +05:30
all_net_family = True
if ( netrules [ ' rule ' ] . get ( family , False ) and
2014-10-20 22:40:42 +02:00
type ( netrules [ ' rule ' ] [ family ] ) == type ( hasher ( ) ) and
sock_type in netrules [ ' rule ' ] [ family ] . keys ( ) and
2014-02-10 22:20:36 -08:00
netrules [ ' rule ' ] [ family ] [ sock_type ] ) :
2013-07-31 19:56:33 +05:30
net_family_sock = True
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if all_net or all_net_family or net_family_sock :
return True
else :
return False
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
def reload_base ( bin_path ) :
if not check_for_apparmor ( ) :
return None
2013-09-22 22:51:30 +05:30
2013-08-01 21:57:27 +05:30
prof_filename = get_profile_filename ( bin_path )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
subprocess . call ( " cat ' %s ' | %s -I %s -r >/dev/null 2>&1 " % ( prof_filename , parser , profile_dir ) , shell = True )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
def reload ( bin_path ) :
bin_path = find_executable ( bin_path )
2013-08-21 11:26:09 +05:30
if not bin_path :
2013-07-31 19:56:33 +05:30
return None
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return reload_base ( bin_path )
def get_include_data ( filename ) :
data = [ ]
2013-08-11 23:16:05 +05:30
filename = profile_dir + ' / ' + filename
2013-08-06 01:53:28 +05:30
if os . path . exists ( filename ) :
with open_file_read ( filename ) as f_in :
2013-07-31 19:56:33 +05:30
data = f_in . readlines ( )
else :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' File Not Found: %s ' ) % filename )
2013-07-31 19:56:33 +05:30
return data
def load_include ( incname ) :
load_includeslist = [ incname ]
if include . get ( incname , { } ) . get ( incname , False ) :
return 0
while load_includeslist :
incfile = load_includeslist . pop ( 0 )
2014-02-10 22:20:36 -08:00
if os . path . isfile ( profile_dir + ' / ' + incfile ) :
2013-09-17 11:46:17 +05:30
data = get_include_data ( incfile )
incdata = parse_profile_data ( data , incfile , True )
#print(incdata)
if not incdata :
2013-09-22 22:51:30 +05:30
# If include is empty, simply push in a placeholder for it
2013-09-17 11:46:17 +05:30
# because other profiles may mention them
incdata = hasher ( )
incdata [ incname ] = hasher ( )
attach_profile_data ( include , incdata )
#If the include is a directory means include all subfiles
2014-02-10 22:20:36 -08:00
elif os . path . isdir ( profile_dir + ' / ' + incfile ) :
load_includeslist + = list ( map ( lambda x : incfile + ' / ' + x , os . listdir ( profile_dir + ' / ' + incfile ) ) )
2015-03-07 13:28:41 +01:00
else :
raise AppArmorException ( " Include file %s not found " % ( profile_dir + ' / ' + incfile ) )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return 0
def rematchfrag ( frag , allow , path ) :
2013-08-11 23:16:05 +05:30
combinedmode = set ( )
combinedaudit = set ( )
2013-07-31 19:56:33 +05:30
matches = [ ]
2013-08-11 23:16:05 +05:30
if not frag :
return combinedmode , combinedaudit , matches
2013-07-31 19:56:33 +05:30
for entry in frag [ allow ] [ ' path ' ] . keys ( ) :
match = matchliteral ( entry , path )
if match :
2013-08-11 23:16:05 +05:30
#print(frag[allow]['path'][entry]['mode'])
combinedmode | = frag [ allow ] [ ' path ' ] [ entry ] . get ( ' mode ' , set ( ) )
combinedaudit | = frag [ allow ] [ ' path ' ] [ entry ] . get ( ' audit ' , set ( ) )
2013-07-31 19:56:33 +05:30
matches . append ( entry )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return combinedmode , combinedaudit , matches
def match_include_to_path ( incname , allow , path ) :
2013-08-11 23:16:05 +05:30
combinedmode = set ( )
combinedaudit = set ( )
2013-07-31 19:56:33 +05:30
matches = [ ]
includelist = [ incname ]
while includelist :
2013-08-11 23:16:05 +05:30
incfile = str ( includelist . pop ( 0 ) )
2014-02-13 10:52:00 -08:00
# ret = load_include(incfile)
load_include ( incfile )
2014-02-10 22:20:36 -08:00
if not include . get ( incfile , { } ) :
2013-08-11 23:16:05 +05:30
continue
2013-09-12 14:42:15 +05:30
cm , am , m = rematchfrag ( include [ incfile ] . get ( incfile , { } ) , allow , path )
2013-08-11 23:16:05 +05:30
#print(incfile, cm, am, m)
2013-07-31 19:56:33 +05:30
if cm :
combinedmode | = cm
combinedaudit | = am
matches + = m
2013-09-22 22:51:30 +05:30
2014-11-26 20:25:07 +01:00
if path in include [ incfile ] [ incfile ] [ allow ] [ ' path ' ] :
2013-07-31 19:56:33 +05:30
combinedmode | = include [ incfile ] [ incfile ] [ allow ] [ ' path ' ] [ path ] [ ' mode ' ]
combinedaudit | = include [ incfile ] [ incfile ] [ allow ] [ ' path ' ] [ path ] [ ' audit ' ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if include [ incfile ] [ incfile ] [ ' include ' ] . keys ( ) :
2013-08-11 23:16:05 +05:30
includelist + = include [ incfile ] [ incfile ] [ ' include ' ] . keys ( )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return combinedmode , combinedaudit , matches
def match_prof_incs_to_path ( frag , allow , path ) :
2013-08-11 23:16:05 +05:30
combinedmode = set ( )
combinedaudit = set ( )
2013-07-31 19:56:33 +05:30
matches = [ ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
includelist = list ( frag [ ' include ' ] . keys ( ) )
while includelist :
incname = includelist . pop ( 0 )
cm , am , m = match_include_to_path ( incname , allow , path )
if cm :
combinedmode | = cm
combinedaudit | = am
matches + = m
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return combinedmode , combinedaudit , matches
def suggest_incs_for_path ( incname , path , allow ) :
2013-08-11 23:16:05 +05:30
combinedmode = set ( )
combinedaudit = set ( )
2013-07-31 19:56:33 +05:30
matches = [ ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
includelist = [ incname ]
while includelist :
inc = includelist . pop ( 0 )
2014-02-10 22:20:36 -08:00
cm , am , m = rematchfrag ( include [ inc ] [ inc ] , ' allow ' , path )
2013-07-31 19:56:33 +05:30
if cm :
combinedmode | = cm
combinedaudit | = am
matches + = m
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if include [ inc ] [ inc ] [ ' allow ' ] [ ' path ' ] . get ( path , False ) :
combinedmode | = include [ inc ] [ inc ] [ ' allow ' ] [ ' path ' ] [ path ] [ ' mode ' ]
combinedaudit | = include [ inc ] [ inc ] [ ' allow ' ] [ ' path ' ] [ path ] [ ' audit ' ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if include [ inc ] [ inc ] [ ' include ' ] . keys ( ) :
includelist + = include [ inc ] [ inc ] [ ' include ' ] . keys ( )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return combinedmode , combinedaudit , matches
def check_qualifiers ( program ) :
if cfg [ ' qualifiers ' ] . get ( program , False ) :
if cfg [ ' qualifiers ' ] [ program ] != ' p ' :
2014-02-10 22:20:36 -08:00
fatal_error ( _ ( " %s is currently marked as a program that should not have its own \n profile. Usually, programs are marked this way if creating a profile for \n them is likely to break the rest of the system. If you know what you \' re \n doing and are certain you want to create a profile for this program, edit \n the corresponding entry in the [qualifiers] section in /etc/apparmor/logprof.conf. " ) % program )
2013-08-21 11:26:09 +05:30
return False
2013-07-31 19:56:33 +05:30
def get_subdirectories ( current_dir ) :
""" Returns a list of all directories directly inside given directory """
2014-02-10 22:20:36 -08:00
if sys . version_info < ( 3 , 0 ) :
2013-07-31 19:56:33 +05:30
return os . walk ( current_dir ) . next ( ) [ 1 ]
else :
return os . walk ( current_dir ) . __next__ ( ) [ 1 ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
def loadincludes ( ) :
incdirs = get_subdirectories ( profile_dir )
for idir in incdirs :
if is_skippable_dir ( idir ) :
continue
for dirpath , dirname , files in os . walk ( profile_dir + ' / ' + idir ) :
if is_skippable_dir ( dirpath ) :
continue
for fi in files :
if is_skippable_file ( fi ) :
continue
else :
2013-08-11 23:16:05 +05:30
fi = dirpath + ' / ' + fi
2014-02-10 22:20:36 -08:00
fi = fi . replace ( profile_dir + ' / ' , ' ' , 1 )
2013-08-11 23:16:05 +05:30
load_include ( fi )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
def glob_common ( path ) :
globs = [ ]
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if re . search ( ' [ \ d \ .]+ \ .so$ ' , path ) or re . search ( ' \ .so \ .[ \ d \ .]+$ ' , path ) :
libpath = path
libpath = re . sub ( ' [ \ d \ .]+ \ .so$ ' , ' *.so ' , libpath )
libpath = re . sub ( ' \ .so \ .[ \ d \ .]+$ ' , ' .so.* ' , libpath )
if libpath != path :
globs . append ( libpath )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
for glob in cfg [ ' globs ' ] :
if re . search ( glob , path ) :
globbedpath = path
2013-08-11 23:16:05 +05:30
globbedpath = re . sub ( glob , cfg [ ' globs ' ] [ glob ] , path )
2013-07-31 19:56:33 +05:30
if globbedpath != path :
globs . append ( globbedpath )
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
return sorted ( set ( globs ) )
def combine_name ( name1 , name2 ) :
if name1 == name2 :
return name1
else :
2014-02-10 22:20:36 -08:00
return ' %s ^ %s ' % ( name1 , name2 )
2013-07-31 19:56:33 +05:30
def split_name ( name ) :
names = name . split ( ' ^ ' )
if len ( names ) == 1 :
return name , name
else :
return names [ 0 ] , names [ 1 ]
2013-08-05 18:55:34 +05:30
def commonprefix ( new , old ) :
2014-02-10 22:20:36 -08:00
match = re . search ( r ' ^([^ \ 0]*)[^ \ 0]*( \ 0 \ 1[^ \ 0]*)*$ ' , ' \0 ' . join ( [ new , old ] ) )
2013-08-05 18:55:34 +05:30
if match :
return match . groups ( ) [ 0 ]
return match
def commonsuffix ( new , old ) :
match = commonprefix ( new [ - 1 : : - 1 ] , old [ - 1 : : - 1 ] )
if match :
return match [ - 1 : : - 1 ]
2013-07-31 19:56:33 +05:30
def matchregexp ( new , old ) :
if re . search ( ' \ { .*( \ ,.*)* \ } ' , old ) :
return None
2013-09-22 22:51:30 +05:30
2013-08-05 18:55:34 +05:30
# if re.search('\[.+\]', old) or re.search('\*', old) or re.search('\?', old):
2013-09-22 22:51:30 +05:30
#
2013-08-05 18:55:34 +05:30
# new_reg = convert_regexp(new)
# old_reg = convert_regexp(old)
2013-09-22 22:51:30 +05:30
#
2013-08-05 18:55:34 +05:30
# pref = commonprefix(new, old)
# if pref:
# if convert_regexp('(*,**)$') in pref:
# pref = pref.replace(convert_regexp('(*,**)$'), '')
# new = new.replace(pref, '', 1)
# old = old.replace(pref, '', 1)
2013-09-22 22:51:30 +05:30
#
2013-08-05 18:55:34 +05:30
# suff = commonsuffix(new, old)
# if suffix:
# pass
new_reg = convert_regexp ( new )
if re . search ( new_reg , old ) :
return True
2013-09-22 22:51:30 +05:30
2013-08-05 18:55:34 +05:30
return None
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
######Initialisations######
2013-08-21 11:26:09 +05:30
conf = apparmor . config . Config ( ' ini ' , CONFDIR )
2013-07-31 19:56:33 +05:30
cfg = conf . read_config ( ' logprof.conf ' )
2013-08-05 18:55:34 +05:30
#print(cfg['settings'])
#if 'default_owner_prompt' in cfg['settings']:
2013-07-31 19:56:33 +05:30
if cfg [ ' settings ' ] . get ( ' default_owner_prompt ' , False ) :
2013-08-05 18:55:34 +05:30
cfg [ ' settings ' ] [ ' default_owner_prompt ' ] = ' '
2013-07-31 19:56:33 +05:30
profile_dir = conf . find_first_dir ( cfg [ ' settings ' ] [ ' profiledir ' ] ) or ' /etc/apparmor.d '
if not os . path . isdir ( profile_dir ) :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( ' Can \' t find AppArmor profiles ' )
2013-07-31 19:56:33 +05:30
extra_profile_dir = conf . find_first_dir ( cfg [ ' settings ' ] [ ' inactive_profiledir ' ] ) or ' /etc/apparmor/profiles/extras/ '
parser = conf . find_first_file ( cfg [ ' settings ' ] [ ' parser ' ] ) or ' /sbin/apparmor_parser '
if not os . path . isfile ( parser ) or not os . access ( parser , os . EX_OK ) :
raise AppArmorException ( ' Can \' t find apparmor_parser ' )
filename = conf . find_first_file ( cfg [ ' settings ' ] [ ' logfiles ' ] ) or ' /var/log/syslog '
if not os . path . isfile ( filename ) :
2014-11-26 20:25:07 +01:00
raise AppArmorException ( ' Can \' t find system log " %s " . ' % ( filename ) )
2013-07-31 19:56:33 +05:30
ldd = conf . find_first_file ( cfg [ ' settings ' ] [ ' ldd ' ] ) or ' /usr/bin/ldd '
if not os . path . isfile ( ldd ) or not os . access ( ldd , os . EX_OK ) :
raise AppArmorException ( ' Can \' t find ldd ' )
logger = conf . find_first_file ( cfg [ ' settings ' ] [ ' logger ' ] ) or ' /bin/logger '
if not os . path . isfile ( logger ) or not os . access ( logger , os . EX_OK ) :
raise AppArmorException ( ' Can \' t find logger ' )