2013-09-28 20:43:06 +05:30
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
#
# 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
2013-07-06 18:57:06 +05:30
from __future__ import with_statement
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-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 = [ ]
## 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
found = False
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
2013-12-20 03:12:58 +05:30
with open_file_read ( file , encoding = ' ascii ' ) as f_in :
2013-07-06 18:57:06 +05:30
for line in f_in :
if ' LD_PRELOAD ' in line or ' LD_LIBRARY_PATH ' in line :
found = True
return found
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
2013-07-04 04:12:04 +05:30
def check_for_apparmor ( ) :
""" Finds and returns the mointpoint for apparmor None otherwise """
filesystem = ' /proc/filesystems '
mounts = ' /proc/mounts '
support_securityfs = False
aa_mountpoint = None
regex_securityfs = re . compile ( ' ^ \ S+ \ s+( \ S+) \ s+securityfs \ s ' )
if valid_path ( filesystem ) :
with open_file_read ( filesystem ) as f_in :
for line in f_in :
if ' securityfs ' in line :
support_securityfs = True
if valid_path ( mounts ) :
with open_file_read ( mounts ) as f_in :
for line in f_in :
if support_securityfs :
2013-07-06 18:57:06 +05:30
match = regex_securityfs . search ( line )
2013-07-04 04:12:04 +05:30
if match :
mountpoint = match . groups ( ) [ 0 ] + ' /apparmor '
if valid_path ( mountpoint ) :
2013-09-22 22:51:30 +05:30
aa_mountpoint = mountpoint
2013-07-04 04:12:04 +05:30
# Check if apparmor is actually mounted there
if not valid_path ( aa_mountpoint + ' /profiles ' ) :
aa_mountpoint = None
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Could not create %s symlink to %s . ' ) % ( link , 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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( " Unable to fork: %s \n \t %s " ) % ( program , 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 ( )
def create_new_profile ( localfile ) :
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
2013-07-09 03:46:26 +05:30
created . append ( localfile )
2014-02-14 11:54:02 -08:00
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
2013-07-09 03:46:26 +05:30
q = dict ( )
q [ ' headers ' ] = [ ' Profile ' , prof_name ]
q [ ' functions ' ] = [ ' CMD_VIEW_PROFILE ' , ' CMD_USE_PROFILE ' , ' CMD_CREATE_PROFILE ' ,
' CMD_ABORT ' , ' CMD_FINISHED ' ]
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-02-10 22:17:21 -08:00
ans , arg = aaui . UI_PromptUser ( q )
2013-07-09 03:46:26 +05:30
p = profile_hash [ options [ arg ] ]
q [ ' selected ' ] = options . index ( options [ arg ] )
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-02-26 23:41:00 +01:00
filelist [ file ] [ ' profiles ' ] [ 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 ) :
2013-09-21 12:36:51 +05:30
matches = RE_PROFILE_START . search ( line ) . groups ( )
profile = matches [ 1 ] or matches [ 3 ]
flags = matches [ 6 ]
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 """
2013-08-10 12:46:22 +05:30
regex_bin_flag = re . compile ( ' ^( \ s*)(( " ??/.+? " ??)|(profile \ s+( " ??.+? " ??))) \ s+((flags=)? \ ((.*) \ ) \ s+)? \ { \ s*(#.*)?$ ' )
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 ]
binary = matches [ 1 ]
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 :
line = ' %s %s %s ( %s ) { %s \n ' % ( space , binary , flag , newflags , comment )
else :
line = ' %s %s { %s \n ' % ( space , binary , 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-02-10 22:17:21 -08:00
aaui . UI_Important ( _ ( ' WARNING: An error occurred while uploading the profile %s \n %s ' ) % ( p , ret ) )
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 [ : ]
q = hasher ( )
q [ ' title ' ] = title
q [ ' headers ' ] = [ ' Repository ' , url ]
q [ ' explanation ' ] = message
q [ ' functions ' ] = [ ' CMD_UPLOAD_CHANGES ' , ' CMD_VIEW_CHANGES ' , ' CMD_ASK_LATER ' ,
' CMD_ASK_NEVER ' , ' CMD_ABORT ' ]
q [ ' default ' ] = ' CMD_VIEW_CHANGES '
q [ ' options ' ] = [ i [ 0 ] for i in profs ]
q [ ' selected ' ] = 0
ans = ' '
while ' CMD_UPLOAD_CHANGES ' not in ans and ' CMD_ASK_NEVER ' not in ans and ' CMD_ASK_LATER ' not in ans :
2014-02-10 22:17:21 -08:00
ans , arg = aaui . UI_PromptUser ( q )
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-02-10 22:17:21 -08:00
aaui . UI_Important ( _ ( ' WARNING: An error occurred while uploading the profile %s \n %s ' ) % ( prof , 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 ' ] :
q = hasher ( )
q [ ' headers ' ] = [ ]
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Profile ' ) , profile ]
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
if default_hat :
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Default Hat ' ) , default_hat ]
2013-09-22 22:51:30 +05:30
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Requested Hat ' ) , uhat ]
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
q [ ' functions ' ] = [ ]
q [ ' functions ' ] . append ( ' CMD_ADDHAT ' )
if default_hat :
q [ ' functions ' ] . append ( ' CMD_USEDEFAULT ' )
q [ ' functions ' ] + = [ ' CMD_DENY ' , ' CMD_ABORT ' , ' CMD_FINISHED ' ]
2013-09-22 22:51:30 +05:30
2013-07-20 04:19:07 +05:30
q [ ' default ' ] = ' CMD_DENY '
if aamode == ' PERMITTING ' :
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-02-10 22:17:21 -08:00
ans = aaui . UI_PromptUser ( q )
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 ) :
nt_name = aa [ profile ] [ hat ]
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 ( )
sev_db . load_variables ( profile )
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
q = hasher ( )
q [ ' headers ' ] = [ ]
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ]
2013-07-23 04:35:51 +05:30
if prog and prog != ' HINT ' :
2013-08-07 14:43:17 +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
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Execute ' ) , exec_target ]
q [ ' headers ' ] + = [ _ ( ' Severity ' ) , severity ]
2013-09-22 22:51:30 +05:30
2013-07-23 04:35:51 +05:30
q [ ' functions ' ] = [ ]
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
2013-10-01 01:30:50 +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-02-10 22:17:21 -08:00
ans = aaui . UI_PromptUser ( q ) [ 0 ] . strip ( )
2013-07-23 04:35:51 +05:30
if ans . startswith ( ' CMD_EXEC_IX_ ' ) :
exec_toggle = not exec_toggle
q [ ' functions ' ] = [ ]
2013-10-01 01:30:50 +05:30
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
2013-07-27 15:28:12 +05:30
aa [ profile ] [ hat ] [ ' path ' ] [ interpreter_path ] [ ' mode ' ] = aa [ profile ] [ hat ] [ ' path ' ] [ interpreter_path ] . get ( ' mode ' , str_to_mode ( ' ix ' ) ) | str_to_mode ( ' ix ' )
2013-09-22 22:51:30 +05:30
2013-08-11 18:30:01 +05:30
aa [ profile ] [ hat ] [ ' path ' ] [ interpreter_path ] [ ' audit ' ] = aa [ profile ] [ hat ] [ ' 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
2013-07-23 04:35:51 +05:30
stub_profile = create_new_profile ( hat )
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 )
q = hasher ( )
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 )
q [ ' options ' ] = [ options ]
q [ ' selected ' ] = default_option - 1
2013-09-22 22:51:30 +05:30
2013-08-07 14:43:17 +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
2013-09-22 22:51:30 +05:30
2013-09-19 10:32:19 +05:30
q [ ' functions ' ] = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_AUDIT_NEW ' ,
' 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
q [ ' default ' ] = ' CMD_DENY '
if aamode == ' PERMITTING ' :
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-02-10 22:17:21 -08:00
ans , selected = aaui . UI_PromptUser ( q )
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
2013-07-27 15:28:12 +05:30
if ans == ' CMD_AUDIT ' :
audit_toggle = not audit_toggle
audit = ' '
if audit_toggle :
2013-09-19 10:32:19 +05:30
q [ ' functions ' ] = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_AUDIT_OFF ' ,
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2013-07-27 15:28:12 +05:30
audit = ' audit '
else :
2013-09-19 10:32:19 +05:30
q [ ' functions ' ] = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_AUDIT_NEW ' ,
' CMD_ABORT ' , ' CMD_FINISHED ' , ]
2013-09-22 22:51:30 +05:30
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ,
_ ( ' 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
if aa [ profile ] [ hat ] [ incname ] :
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-02-10 22:20:36 -08:00
q = hasher ( )
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] = [ _ ( ' Profile ' ) , combine_name ( profile , hat ) ,
_ ( ' 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
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 )
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Mode ' ) , s ]
2013-09-22 22:51:30 +05:30
2013-08-07 14:43:17 +05:30
q [ ' headers ' ] + = [ _ ( ' Severity ' ) , severity ]
2013-07-27 15:28:12 +05:30
q [ ' options ' ] = options
q [ ' selected ' ] = default_option - 1
2013-09-19 10:32:19 +05:30
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 ' ]
2013-07-27 15:28:12 +05:30
q [ ' default ' ] = ' CMD_DENY '
if aamode == ' PERMITTING ' :
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-02-10 22:17:21 -08:00
ans , selected = aaui . UI_PromptUser ( q )
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 :
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-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Adding %s %s to profile ' ) % ( path , 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-02-10 22:20:36 -08:00
ynprompt = _ ( ' The specified path does not match this log entry: \n \n Log Entry: %s \n Entered Path: %s \n Do you really want to use this path? ' ) % ( path , 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 )
options . append ( ans )
default_option = len ( options )
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 )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if newpath not in options :
options . append ( newpath )
default_option = len ( options )
2013-08-26 00:23:59 +05:30
else :
default_option = options . index ( newpath ) + 1
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 )
2013-09-22 22:51:30 +05:30
2013-07-27 15:28:12 +05:30
if newpath not in options :
options . append ( newpath )
default_option = len ( options )
2013-08-26 00:23:59 +05:30
else :
default_option = options . index ( newpath ) + 1
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
2013-07-28 08:23:46 +05:30
for sock_type in sorted ( log_dict [ profile ] [ 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 )
2013-07-27 15:28:12 +05:30
q = hasher ( )
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 ) )
q [ ' options ' ] = options
q [ ' selected ' ] = default_option - 1
2013-09-22 22:51:30 +05:30
2013-08-07 14:43:17 +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
2013-09-19 10:32:19 +05:30
q [ ' functions ' ] = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_IGNORE_ENTRY ' , ' CMD_AUDIT_NEW ' ,
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2013-07-27 15:28:12 +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 ' :
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-02-10 22:17:21 -08:00
ans , selected = aaui . UI_PromptUser ( q )
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 '
q [ ' functions ' ] = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_AUDIT_OFF ' ,
' CMD_ABORT ' , ' CMD_FINISHED ' ]
else :
q [ ' functions ' ] = [ ' CMD_ALLOW ' , ' CMD_DENY ' , ' CMD_AUDIT_NEW ' ,
' CMD_ABORT ' , ' CMD_FINISHED ' ]
2013-08-07 14:43:17 +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 ' :
selection = options [ selected ]
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-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Adding network access %s %s to profile. ' ) % ( family , 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-02-10 22:17:21 -08:00
aaui . UI_Info ( _ ( ' Denying network access %s %s to profile ' ) % ( family , 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
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 ( ) :
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
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
2013-07-30 20:13:08 +05:30
if valid_include ( profile , incname ) and match_net_include ( incname , family , type ) :
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 ) :
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 :
q = hasher ( )
q [ ' title ' ] = ' Changed Local Profiles '
q [ ' headers ' ] = [ ]
2013-08-07 14:43:17 +05:30
q [ ' explanation ' ] = _ ( ' The following local profiles were changed. Would you like to save them? ' )
2013-08-21 11:26:09 +05:30
q [ ' functions ' ] = [ ' CMD_SAVE_CHANGES ' , ' CMD_SAVE_SELECTED ' , ' CMD_VIEW_CHANGES ' , ' CMD_VIEW_CHANGES_CLEAN ' , ' CMD_ABORT ' ]
2013-07-28 08:23:46 +05:30
q [ ' default ' ] = ' CMD_VIEW_CHANGES '
q [ ' options ' ] = changed
q [ ' selected ' ] = 0
ans = ' '
arg = None
while ans != ' CMD_SAVE_CHANGES ' :
2013-09-22 15:01:34 +05:30
if not changed :
return
2014-02-10 22:17:21 -08:00
ans , arg = aaui . UI_PromptUser ( q )
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 15:01:34 +05:30
#changed.pop(profile_name)
2013-08-21 11:26:09 +05:30
#q['options'] = changed
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
2013-07-28 08:23:46 +05:30
for profile_name in changed_list :
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
# rpm backup files, dotfiles, emacs backup files should not be processed
# The skippable files type needs be synced with apparmor initscript
def is_skippable_file ( path ) :
""" Returns True if filename matches something to be skipped """
if ( re . search ( ' (^|/) \ .[^/]*$ ' , path ) or re . search ( ' \ .rpm(save|new)$ ' , path )
2014-02-10 22:20:36 -08:00
or re . search ( ' \ .dpkg-(old|new)$ ' , path ) or re . search ( ' \ .swp$ ' , path )
or path [ - 1 ] == ' ~ ' or path == ' README ' ) :
2013-07-28 08:23:46 +05:30
return True
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
2013-08-18 14:13:46 +05:30
## Profile parsing regex
RE_PROFILE_START = re . compile ( ' ^ \ s*(( " ??/.+? " ??)|(profile \ s+( " ??.+? " ??))) \ s+((flags=)? \ ((.+) \ ) \ s+)? \ { \ s*(#.*)?$ ' )
RE_PROFILE_END = re . compile ( ' ^ \ s* \ } \ s*(#.*)?$ ' )
RE_PROFILE_CAP = re . compile ( ' ^ \ s*(audit \ s+)?(allow \ s+|deny \ s+)?capability \ s+( \ S+) \ s*, \ s*(#.*)?$ ' )
RE_PROFILE_LINK = re . compile ( ' ^ \ s*(audit \ s+)?(allow \ s+|deny \ s+)?link \ s+(((subset)|(<=)) \ s+)?([ \" \ @ \ /].*? " ??) \ s+-> \ s*([ \" \ @ \ /].*? " ??) \ s*, \ s*(#.*)?$ ' )
RE_PROFILE_CHANGE_PROFILE = re . compile ( ' ^ \ s*change_profile \ s+-> \ s*( " ??.+? " ??),(#.*)?$ ' )
RE_PROFILE_ALIAS = re . compile ( ' ^ \ s*alias \ s+( " ??.+? " ??) \ s+-> \ s*( " ??.+? " ??) \ s*,(#.*)?$ ' )
RE_PROFILE_RLIMIT = re . compile ( ' ^ \ s*set \ s+rlimit \ s+(.+) \ s+(<=)? \ s*(.+) \ s*,(#.*)?$ ' )
RE_PROFILE_BOOLEAN = re . compile ( ' ^ \ s*( \ $ \ { ? \ w* \ }?) \ s*= \ s*(true|false) \ s*,? \ s*(#.*)?$ ' , flags = re . IGNORECASE )
RE_PROFILE_VARIABLE = re . compile ( ' ^ \ s*(@ \ { ? \ w+ \ }?) \ s*( \ +?=) \ s*(@*.+?) \ s*,? \ s*(#.*)?$ ' )
RE_PROFILE_CONDITIONAL = re . compile ( ' ^ \ s*if \ s+(not \ s+)?( \ $ \ { ? \ w* \ }?) \ s* \ { \ s*(#.*)?$ ' )
RE_PROFILE_CONDITIONAL_VARIABLE = re . compile ( ' ^ \ s*if \ s+(not \ s+)?defined \ s+(@ \ { ? \ w+ \ }?) \ s* \ { \ s*(#.*)?$ ' )
RE_PROFILE_CONDITIONAL_BOOLEAN = re . compile ( ' ^ \ s*if \ s+(not \ s+)?defined \ s+( \ $ \ { ? \ w+ \ }?) \ s* \ { \ s*(#.*)?$ ' )
RE_PROFILE_PATH_ENTRY = re . compile ( ' ^ \ s*(audit \ s+)?(allow \ s+|deny \ s+)?(owner \ s+)?([ \" @/].*?) \ s+( \ S+)( \ s+-> \ s*(.*?))? \ s*, \ s*(#.*)?$ ' )
RE_PROFILE_NETWORK = re . compile ( ' ^ \ s*(audit \ s+)?(allow \ s+|deny \ s+)?network(.*) \ s*(#.*)?$ ' )
RE_PROFILE_CHANGE_HAT = re . compile ( ' ^ \ s* \ ^( \" ??.+? \" ??) \ s*, \ s*(#.*)?$ ' )
RE_PROFILE_HAT_DEF = re . compile ( ' ^ \ s* \ ^( \" ??.+? \" ??) \ s+((flags=)? \ ((.+) \ ) \ s+)* \ { \ s*(#.*)?$ ' )
RE_NETWORK_FAMILY_TYPE = re . compile ( ' \ s+( \ S+) \ s+( \ S+) \ s*,$ ' )
RE_NETWORK_FAMILY = re . compile ( ' \ s+( \ S+) \ s*,$ ' )
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
RE_PROFILE_DBUS = re . compile ( ' ^ \ s*(audit \ s+)?(allow \ s+|deny \ s+)?(dbus[^#]* \ s*,) \ s*(#.*)?$ ' )
# match anything that's not " or #, or matching quotes with anything except quotes inside
__re_no_or_quoted_hash = ' ([^# " ]| " [^ " ]* " )* '
RE_RULE_HAS_COMMA = re . compile ( ' ^ ' + __re_no_or_quoted_hash +
' , \ s*(#.*)?$ ' ) # match comma plus any trailing comment
RE_HAS_COMMENT_SPLIT = re . compile ( ' ^(?P<not_comment> ' + __re_no_or_quoted_hash + ' ) ' + # store in 'not_comment' group
' (?P<comment>#.*)$ ' ) # match trailing comment and store in 'comment' group
2013-08-18 14:13:46 +05:30
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 ) :
matches = RE_PROFILE_START . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if profile :
2013-08-06 01:53:28 +05:30
#print(profile, hat)
if profile != hat or not matches [ 3 ] :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' %s profile in %s contains syntax errors in line: %s . ' ) % ( profile , file , lineno + 1 ) )
2013-07-30 20:13:08 +05:30
# Keep track of the start of a profile
if profile and profile == hat and matches [ 3 ] :
# local profile
hat = matches [ 3 ]
in_contained_hat = True
2014-02-10 22:20:36 -08:00
profile_data [ profile ] [ hat ] [ ' profile ' ] = True
2013-07-30 20:13:08 +05:30
else :
if matches [ 1 ] :
profile = matches [ 1 ]
else :
profile = matches [ 3 ]
2013-08-07 14:43:17 +05:30
#print(profile)
if len ( profile . split ( ' // ' ) ) > = 2 :
profile , hat = profile . split ( ' // ' ) [ : 2 ]
else :
hat = None
2013-07-30 20:13:08 +05:30
in_contained_hat = False
if hat :
profile_data [ profile ] [ hat ] [ ' external ' ] = True
else :
hat = profile
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
flags = matches [ 6 ]
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
profile = strip_quotes ( profile )
if hat :
hat = strip_quotes ( hat )
# 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 ( )
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected End of Profile reached in file: %s line: %s ' ) % ( file , 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 ) :
matches = RE_PROFILE_CAP . search ( line ) . groups ( )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if not profile :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected capability entry found in file: %s line: %s ' ) % ( file , 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
capability = matches [ 2 ]
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected link entry found in file: %s line: %s ' ) % ( file , 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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected change profile entry found in file: %s line: %s ' ) % ( file , lineno + 1 ) )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
cp = strip_quotes ( matches [ 0 ] )
profile_data [ profile ] [ hat ] [ ' changes_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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected rlimit entry found in file: %s line: %s ' ) % ( file , 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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected boolean definition found in file: %s line: %s ' ) % ( file , 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 ] = [ ]
2013-08-06 01:53:28 +05:30
store_list_var ( profile_data [ profile ] [ ' lvar ' ] , list_var , value , var_operation )
2013-07-30 20:13:08 +05:30
else :
if not filelist [ file ] . get ( ' lvar ' , False ) :
filelist [ file ] [ ' lvar ' ] [ list_var ] = [ ]
2013-08-06 01:53:28 +05:30
store_list_var ( filelist [ file ] [ ' lvar ' ] , list_var , value , var_operation )
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
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected path entry found in file: %s line: %s ' ) % ( file , 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
2013-07-30 20:13:08 +05:30
path = matches [ 3 ] . strip ( )
mode = matches [ 4 ]
nt_name = matches [ 6 ]
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Invalid Regex %s in file: %s line: %s ' ) % ( path , file , 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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Invalid mode %s in file: %s line: %s ' ) % ( mode , file , 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
2013-07-30 20:13:08 +05:30
if nt_name :
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' to ' ] = nt_name
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
if audit :
2013-08-11 23:16:05 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' audit ' ] = profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' audit ' , set ( ) ) | tmpmode
2013-07-30 20:13:08 +05:30
else :
2013-08-11 23:16:05 +05:30
profile_data [ profile ] [ hat ] [ allow ] [ ' path ' ] [ path ] [ ' audit ' ] = set ( )
2013-09-22 22:51:30 +05:30
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected network entry found in file: %s line: %s ' ) % ( file , 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 :
raise AppArmorException ( _ ( ' Syntax Error: Unexpected dbus entry found in file: %s line: %s ' ) % ( file , lineno + 1 ) )
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
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected change hat declaration found in file: %s line: %s ' ) % ( file , 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
matches = RE_PROFILE_HAT_DEF . search ( line ) . groups ( )
if not profile :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unexpected hat definition found in file: %s line: %s ' ) % ( file , lineno + 1 ) )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
in_contained_hat = True
hat = matches [ 0 ]
hat = strip_quotes ( hat )
flags = matches [ 3 ]
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Error: Multiple definitions for hat %s in profile %s . ' ) % ( hat , 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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Syntax Error: Unknown line found in file: %s line: %s ' ) % ( file , 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 :
2013-09-21 01:08:34 +05:30
raise AppArmorException ( _ ( " Syntax Error: Missing ' } ' . Reached end of file %s while inside profile %s " ) % ( file , profile ) )
2013-09-22 22:51:30 +05:30
2013-07-30 20:13:08 +05:30
return profile_data
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)
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
2013-08-06 01:53:28 +05:30
def store_list_var ( var , list_var , value , var_operation ) :
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' An existing variable redefined: %s ' ) % list_var )
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-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Values added to a non-existing variable: %s ' ) % list_var )
2013-08-11 15:22:07 +05:30
else :
2014-02-10 22:20:36 -08:00
raise AppArmorException ( _ ( ' Unknown variable operation: %s ' ) % var_operation )
2013-08-06 01:53:28 +05:30
2013-07-30 20:13:08 +05:30
def strip_quotes ( data ) :
2014-02-10 22:20:36 -08:00
if data [ 0 ] + data [ - 1 ] == ' " " ' :
2013-08-06 01:53:28 +05:30
return data [ 1 : - 1 ]
else :
return data
2013-09-22 22:51:30 +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 ) :
2013-07-30 20:13:08 +05:30
pre = ' ' * depth
data = [ ]
name = quote_if_needed ( name )
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
if ( not embedded_hat and re . search ( ' ^[^/]|^ " [^/] ' , name ) ) or ( embedded_hat and re . search ( ' ^[^^] ' , name ) ) :
2013-07-30 20:13:08 +05:30
name = ' profile %s ' % name
2013-09-22 22:51:30 +05:30
2013-07-31 19:56:33 +05:30
if write_flags and prof_data [ ' flags ' ] :
2013-08-11 23:16:05 +05:30
data . append ( ' %s %s flags=( %s ) { ' % ( pre , name , prof_data [ ' flags ' ] ) )
2013-07-30 20:13:08 +05:30
else :
data . append ( ' %s %s { ' % ( pre , name ) )
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-02-10 22:20:36 -08:00
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 ( ) ) :
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 ] :
audit = ' audit '
data . append ( ' %s %s %s network %s ' % ( pre , audit , allowstr , fam ) )
else :
for typ in sorted ( prof_data [ allow ] [ ' netdomain ' ] [ ' rule ' ] [ fam ] . keys ( ) ) :
if prof_data [ allow ] [ ' netdomain ' ] [ ' audit ' ] [ fam ] . get ( typ , False ) :
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 ' )
data + = write_net_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 ( ) ) :
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 ' ]
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
2013-07-31 19:56:33 +05:30
if tmpmode & tmpaudit :
modestr = mode_to_str ( tmpmode & tmpaudit )
path = quote_if_needed ( path )
2014-02-10 22:20:36 -08:00
data . append ( ' %s audit %s %s %s %s %s , ' % ( pre , allowstr , ownerstr , 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 )
path = quote_if_needed ( path )
2014-02-10 22:20:36 -08:00
data . append ( ' %s %s %s %s %s %s , ' % ( pre , allowstr , ownerstr , 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 )
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 ) :
comment = profile_data [ name ] [ ' initial_comment ' ]
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
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 ,
2013-08-19 12:37:47 +05:30
' link ' : write_links ,
' path ' : write_paths ,
' change_profile ' : write_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 ,
2013-08-19 12:37:47 +05:30
' link ' : False ,
' path ' : False ,
' change_profile ' : False ,
' include_local_started ' : False ,
2014-02-10 22:20:36 -08:00
}
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 ) :
matches = RE_PROFILE_START . search ( line ) . groups ( )
if profile and profile == hat and matches [ 3 ] :
hat = matches [ 3 ]
in_contained_hat = True
if write_prof_data [ profile ] [ hat ] [ ' profile ' ] :
pass
else :
if matches [ 1 ] :
profile = matches [ 1 ]
else :
profile = matches [ 3 ]
if len ( profile . split ( ' // ' ) ) > = 2 :
profile , hat = profile . split ( ' // ' ) [ : 2 ]
else :
hat = None
in_contained_hat = False
if hat and not write_prof_data [ profile ] [ hat ] [ ' external ' ] :
correct = False
else :
hat = profile
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
flags = matches [ 6 ]
profile = strip_quotes ( profile )
if hat :
hat = strip_quotes ( hat )
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 :
2013-08-19 12:37:47 +05:30
depth = len ( line ) - len ( line . lstrip ( ) )
if True in segments . values ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
2013-09-22 22:51:30 +05:30
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
data + = write_alias ( write_prof_data [ name ] , depth )
data + = write_list_vars ( write_prof_data [ name ] , depth )
data + = write_includes ( write_prof_data [ name ] , depth )
data + = write_rlimits ( write_prof_data , depth )
data + = write_capabilities ( write_prof_data [ name ] , depth )
data + = write_netdomain ( write_prof_data [ name ] , depth )
2014-03-07 09:58:54 -08:00
data + = write_dbus ( write_prof_data [ name ] , depth )
2013-08-19 12:37:47 +05:30
data + = write_links ( write_prof_data [ name ] , depth )
data + = write_paths ( write_prof_data [ name ] , depth )
data + = write_change_profile ( 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
2013-08-18 14:13:46 +05:30
capability = matches [ 2 ]
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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-02-10 22:20:36 -08:00
if not write_prof_data [ hat ] [ ' changes_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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 :
store_list_var ( var_set , list_var , value , var_operation )
if not var_set [ list_var ] == write_prof_data [ ' lvar ' ] . get ( list_var , False ) :
correct = False
else :
store_list_var ( var_set , list_var , value , var_operation )
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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
2013-08-18 14:13:46 +05:30
elif RE_PROFILE_PATH_ENTRY . search ( line ) :
matches = RE_PROFILE_PATH_ENTRY . search ( line ) . groups ( )
audit = False
if matches [ 0 ] :
audit = True
allow = ' allow '
if matches [ 1 ] and matches [ 1 ] . split ( ) == ' deny ' :
allow = ' deny '
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
user = False
if matches [ 2 ] :
user = True
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
path = matches [ 3 ] . strip ( )
mode = matches [ 4 ]
nt_name = matches [ 6 ]
if nt_name :
nt_name = nt_name . strip ( )
2013-09-22 22:51:30 +05:30
2013-08-18 14:13:46 +05:30
tmpmode = set ( )
if user :
2014-02-10 22:20:36 -08:00
tmpmode = str_to_mode ( ' %s :: ' % mode )
2013-08-18 14:13:46 +05:30
else :
tmpmode = str_to_mode ( mode )
2013-09-22 22:51:30 +05:30
2013-09-21 18:50:00 +05:30
if not write_prof_data [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' mode ' , set ( ) ) & tmpmode :
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 nt_name and not write_prof_data [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' to ' , False ) == nt_name :
correct = False
2013-09-22 22:51:30 +05:30
2013-09-21 18:50:00 +05:30
if audit and not write_prof_data [ hat ] [ allow ] [ ' path ' ] [ path ] . get ( ' audit ' , set ( ) ) & tmpmode :
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 [ ' path ' ] and True in segments . values ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ( ) :
for segs in list ( filter ( lambda x : segments [ x ] , segments . keys ( ) ) ) :
depth = len ( line ) - len ( line . lstrip ( ) )
2014-02-10 22:20:36 -08:00
data + = write_methods [ segs ] ( write_prof_data [ name ] , int ( depth / 2 ) )
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
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 ) :
2013-09-22 22:51:30 +05:30
matches = RE_PROFILE_HAT_DEF . search ( line ) . groups ( )
2013-08-18 14:13:46 +05:30
in_contained_hat = True
hat = matches [ 0 ]
hat = strip_quotes ( hat )
flags = matches [ 3 ]
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-02-10 22:20:36 -08:00
type ( netrules [ ' rule ' ] [ family ] ) == dict and
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 ) ) )
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
2013-07-31 19:56:33 +05:30
if include [ incfile ] [ incfile ] [ allow ] [ ' path ' ] [ path ] :
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 ) :
raise AppArmorException ( ' Can \' t find system log. ' )
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 ' )