Accepting request 511329 from security:apparmor
- don't rely on implementation details for reload in %post - add JSON support. Required for FATE#323380. (apparmor-yast-cleanup.patch, apparmor-json-support.patch) OBS-URL: https://build.opensuse.org/request/show/511329 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/apparmor?expand=0&rev=102
This commit is contained in:
commit
dcc7263ed5
307
apparmor-json-support.patch
Normal file
307
apparmor-json-support.patch
Normal file
@ -0,0 +1,307 @@
|
||||
commit aa95d7c9d4b0a7386ac52ad8dbcb28922198c8b7
|
||||
Author: Goldwyn Rodrigues <rgoldwyn@suse.de>
|
||||
Date: Thu Jun 15 18:22:43 2017 +0200
|
||||
|
||||
json support for logprof and genprof
|
||||
|
||||
From: Goldwyn Rodrigues <rgoldwyn@suse.com>
|
||||
|
||||
Provides json support to tools in order to interact with other
|
||||
utilities such as Yast.
|
||||
|
||||
The JSON output is one per line, in order to differentiate between
|
||||
multiple records. Each JSON record has a "dialog" entry which defines
|
||||
the type of message passed. A response must contain the "dialog"
|
||||
entry. "info" message does not require a response.
|
||||
|
||||
"apparmor-json-version" added in order to identify the communication
|
||||
protocol version for future updates.
|
||||
|
||||
This is based on work done by Christian Boltz.
|
||||
|
||||
Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
|
||||
|
||||
|
||||
Acked-by: Christian Boltz <apparmor@cboltz.de>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
|
||||
diff --git a/utils/aa-genprof b/utils/aa-genprof
|
||||
index e2e65442..c9415e10 100755
|
||||
--- a/utils/aa-genprof
|
||||
+++ b/utils/aa-genprof
|
||||
@@ -61,8 +61,12 @@ parser = argparse.ArgumentParser(description=_('Generate profile for the given p
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-f', '--file', type=str, help=_('path to logfile'))
|
||||
parser.add_argument('program', type=str, help=_('name of program to profile'))
|
||||
+parser.add_argument('-j', '--json', action="store_true", help=_('Input and Output in JSON'))
|
||||
args = parser.parse_args()
|
||||
|
||||
+if args.json:
|
||||
+ aaui.set_json_mode()
|
||||
+
|
||||
profiling = args.program
|
||||
profiledir = args.dir
|
||||
|
||||
diff --git a/utils/aa-logprof b/utils/aa-logprof
|
||||
index c05cbef3..0ff37652 100755
|
||||
--- a/utils/aa-logprof
|
||||
+++ b/utils/aa-logprof
|
||||
@@ -16,6 +16,7 @@ import argparse
|
||||
import os
|
||||
|
||||
import apparmor.aa as apparmor
|
||||
+import apparmor.ui as aaui
|
||||
|
||||
# setup exception handling
|
||||
from apparmor.fail import enable_aa_exception_handler
|
||||
@@ -29,8 +30,12 @@ parser = argparse.ArgumentParser(description=_('Process log entries to generate
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-f', '--file', type=str, help=_('path to logfile'))
|
||||
parser.add_argument('-m', '--mark', type=str, help=_('mark in the log to start processing after'))
|
||||
+parser.add_argument('-j', '--json', action='store_true', help=_('Input and Output in JSON'))
|
||||
args = parser.parse_args()
|
||||
|
||||
+if args.json:
|
||||
+ aaui.set_json_mode()
|
||||
+
|
||||
profiledir = args.dir
|
||||
logmark = args.mark or ''
|
||||
|
||||
diff --git a/utils/apparmor/ui.py b/utils/apparmor/ui.py
|
||||
index f25fff31..0010f468 100644
|
||||
--- a/utils/apparmor/ui.py
|
||||
+++ b/utils/apparmor/ui.py
|
||||
@@ -1,5 +1,7 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
+# Copyright (C) 2017 Christian Boltz <apparmor@cboltz.de>
|
||||
+# Copyright (C) 2017 SUSE Linux
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -11,6 +13,8 @@
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
+
|
||||
+import json
|
||||
import sys
|
||||
import re
|
||||
import readline
|
||||
@@ -24,14 +28,32 @@ _ = init_translation()
|
||||
# Set up UI logger for separate messages from UI module
|
||||
debug_logger = DebugLogger('UI')
|
||||
|
||||
-# The operating mode: yast or text, text by default
|
||||
-UI_mode = 'text'
|
||||
-
|
||||
# If Python3, wrap input in raw_input so make check passes
|
||||
if not 'raw_input' in dir(__builtins__): raw_input = input
|
||||
|
||||
ARROWS = {'A': 'UP', 'B': 'DOWN', 'C': 'RIGHT', 'D': 'LEFT'}
|
||||
|
||||
+UI_mode = 'text'
|
||||
+
|
||||
+def write_json(jsonout):
|
||||
+ print(json.dumps(jsonout, sort_keys=False, separators=(',', ': ')))
|
||||
+ sys.stdout.flush()
|
||||
+
|
||||
+def set_json_mode():
|
||||
+ global UI_mode
|
||||
+ UI_mode = 'json'
|
||||
+ jsonout = {'dialog': 'apparmor-json-version', 'data': '2.12'}
|
||||
+ write_json(jsonout)
|
||||
+
|
||||
+# reads the response on command line for json and verifies the response
|
||||
+# for the dialog type
|
||||
+def json_response(dialog_type):
|
||||
+ string = raw_input('\n')
|
||||
+ rh = json.loads(string.strip())
|
||||
+ if rh["dialog"] != dialog_type:
|
||||
+ raise AppArmorException('Expected response %s got %s.' % (dialog_type, string))
|
||||
+ return rh
|
||||
+
|
||||
def getkey():
|
||||
key = readkey()
|
||||
if key == '\x1B':
|
||||
@@ -44,12 +66,18 @@ def getkey():
|
||||
|
||||
def UI_Info(text):
|
||||
debug_logger.info(text)
|
||||
- if UI_mode == 'text':
|
||||
+ if UI_mode == 'json':
|
||||
+ jsonout = {'dialog': 'info', 'data': text}
|
||||
+ write_json(jsonout)
|
||||
+ else: # text mode
|
||||
sys.stdout.write(text + '\n')
|
||||
|
||||
def UI_Important(text):
|
||||
debug_logger.debug(text)
|
||||
- if UI_mode == 'text':
|
||||
+ if UI_mode == 'json':
|
||||
+ jsonout = {'dialog': 'important', 'data': text}
|
||||
+ write_json(jsonout)
|
||||
+ else: # text mode
|
||||
sys.stdout.write('\n' + text + '\n')
|
||||
|
||||
def get_translated_hotkey(translated, cmsg=''):
|
||||
@@ -67,14 +95,18 @@ def get_translated_hotkey(translated, cmsg=''):
|
||||
def UI_YesNo(text, default):
|
||||
debug_logger.debug('UI_YesNo: %s: %s %s' % (UI_mode, text, default))
|
||||
default = default.lower()
|
||||
- ans = None
|
||||
- if UI_mode == 'text':
|
||||
- yes = CMDS['CMD_YES']
|
||||
- no = CMDS['CMD_NO']
|
||||
- yeskey = get_translated_hotkey(yes).lower()
|
||||
- nokey = get_translated_hotkey(no).lower()
|
||||
- ans = 'XXXINVALIDXXX'
|
||||
- while ans not in ['y', 'n']:
|
||||
+ yes = CMDS['CMD_YES']
|
||||
+ no = CMDS['CMD_NO']
|
||||
+ yeskey = get_translated_hotkey(yes).lower()
|
||||
+ nokey = get_translated_hotkey(no).lower()
|
||||
+ ans = 'XXXINVALIDXXX'
|
||||
+ while ans not in ['y', 'n']:
|
||||
+ if UI_mode == 'json':
|
||||
+ jsonout = {'dialog': 'yesno', 'text': text, 'default': default}
|
||||
+ write_json(jsonout)
|
||||
+ hm = json_response('yesno')
|
||||
+ ans = hm['response_key']
|
||||
+ else: # text mode
|
||||
sys.stdout.write('\n' + text + '\n')
|
||||
if default == 'y':
|
||||
sys.stdout.write('\n[%s] / %s\n' % (yes, no))
|
||||
@@ -102,18 +134,22 @@ def UI_YesNo(text, default):
|
||||
def UI_YesNoCancel(text, default):
|
||||
debug_logger.debug('UI_YesNoCancel: %s: %s %s' % (UI_mode, text, default))
|
||||
default = default.lower()
|
||||
- ans = None
|
||||
- if UI_mode == 'text':
|
||||
- yes = CMDS['CMD_YES']
|
||||
- no = CMDS['CMD_NO']
|
||||
- cancel = CMDS['CMD_CANCEL']
|
||||
-
|
||||
- yeskey = get_translated_hotkey(yes).lower()
|
||||
- nokey = get_translated_hotkey(no).lower()
|
||||
- cancelkey = get_translated_hotkey(cancel).lower()
|
||||
-
|
||||
- ans = 'XXXINVALIDXXX'
|
||||
- while ans not in ['c', 'n', 'y']:
|
||||
+ yes = CMDS['CMD_YES']
|
||||
+ no = CMDS['CMD_NO']
|
||||
+ cancel = CMDS['CMD_CANCEL']
|
||||
+
|
||||
+ yeskey = get_translated_hotkey(yes).lower()
|
||||
+ nokey = get_translated_hotkey(no).lower()
|
||||
+ cancelkey = get_translated_hotkey(cancel).lower()
|
||||
+
|
||||
+ ans = 'XXXINVALIDXXX'
|
||||
+ while ans not in ['c', 'n', 'y']:
|
||||
+ if UI_mode == 'json':
|
||||
+ jsonout = {'dialog': 'yesnocancel', 'text': text, 'default': default}
|
||||
+ write_json(jsonout)
|
||||
+ hm = json_response('yesnocancel')
|
||||
+ ans = hm['response_key']
|
||||
+ else: # text mode
|
||||
sys.stdout.write('\n' + text + '\n')
|
||||
if default == 'y':
|
||||
sys.stdout.write('\n[%s] / %s / %s\n' % (yes, no, cancel))
|
||||
@@ -148,7 +184,11 @@ def UI_YesNoCancel(text, default):
|
||||
def UI_GetString(text, default):
|
||||
debug_logger.debug('UI_GetString: %s: %s %s' % (UI_mode, text, default))
|
||||
string = default
|
||||
- if UI_mode == 'text':
|
||||
+ if UI_mode == 'json':
|
||||
+ jsonout = {'dialog': 'getstring', 'text': text, 'default': default}
|
||||
+ write_json(jsonout)
|
||||
+ string = json_response('getstring')["response"]
|
||||
+ else: # text mode
|
||||
readline.set_startup_hook(lambda: readline.insert_text(default))
|
||||
try:
|
||||
string = raw_input('\n' + text)
|
||||
@@ -161,15 +201,18 @@ def UI_GetString(text, default):
|
||||
def UI_GetFile(file):
|
||||
debug_logger.debug('UI_GetFile: %s' % UI_mode)
|
||||
filename = None
|
||||
- if UI_mode == 'text':
|
||||
+ if UI_mode == 'json':
|
||||
+ jsonout = {'dialog': 'getfile', 'text': file['description']}
|
||||
+ write_json(jsonout)
|
||||
+ filename = json_response('getfile')["response"]
|
||||
+ else: # text mode
|
||||
sys.stdout.write(file['description'] + '\n')
|
||||
filename = sys.stdin.read()
|
||||
return filename
|
||||
|
||||
def UI_BusyStart(message):
|
||||
debug_logger.debug('UI_BusyStart: %s' % UI_mode)
|
||||
- if UI_mode == 'text':
|
||||
- UI_Info(message)
|
||||
+ UI_Info(message)
|
||||
|
||||
def UI_BusyStop():
|
||||
debug_logger.debug('UI_BusyStop: %s' % UI_mode)
|
||||
@@ -254,8 +297,7 @@ class PromptQuestion(object):
|
||||
def promptUser(self, params=''):
|
||||
cmd = None
|
||||
arg = None
|
||||
- if UI_mode == 'text':
|
||||
- cmd, arg = self.Text_PromptUser()
|
||||
+ cmd, arg = self.Text_PromptUser()
|
||||
if cmd == 'CMD_ABORT':
|
||||
confirm_and_abort()
|
||||
cmd = 'XXXINVALIDXXX'
|
||||
@@ -324,6 +366,17 @@ class PromptQuestion(object):
|
||||
function_regexp += ')$'
|
||||
|
||||
ans = 'XXXINVALIDXXX'
|
||||
+ hdict = dict()
|
||||
+ jsonprompt = {
|
||||
+ 'dialog': 'promptuser',
|
||||
+ 'title': title,
|
||||
+ 'headers': hdict,
|
||||
+ 'explanation': explanation,
|
||||
+ 'options': options,
|
||||
+ 'menu_items': menu_items,
|
||||
+ 'default_key': default_key,
|
||||
+ }
|
||||
+
|
||||
while not re.search(function_regexp, ans, flags=re.IGNORECASE):
|
||||
|
||||
prompt = '\n'
|
||||
@@ -335,6 +388,7 @@ class PromptQuestion(object):
|
||||
while header_copy:
|
||||
header = header_copy.pop(0)
|
||||
value = header_copy.pop(0)
|
||||
+ hdict[header] = value
|
||||
prompt += formatstr % (header + ':', value)
|
||||
prompt += '\n'
|
||||
|
||||
@@ -352,9 +406,14 @@ class PromptQuestion(object):
|
||||
|
||||
prompt += ' / '.join(menu_items)
|
||||
|
||||
- sys.stdout.write(prompt + '\n')
|
||||
-
|
||||
- ans = getkey().lower()
|
||||
+ if UI_mode == 'json':
|
||||
+ write_json(jsonprompt)
|
||||
+ hm = json_response('promptuser')
|
||||
+ ans = hm["response_key"]
|
||||
+ selected = hm["selected"]
|
||||
+ else: # text mode
|
||||
+ sys.stdout.write(prompt + '\n')
|
||||
+ ans = getkey().lower()
|
||||
|
||||
if ans:
|
||||
if ans == 'up':
|
||||
@@ -381,7 +440,7 @@ class PromptQuestion(object):
|
||||
selected = ans - 1
|
||||
ans = 'XXXINVALIDXXX'
|
||||
|
||||
- if keys.get(ans, False) == 'CMD_HELP':
|
||||
+ if keys.get(ans, False) == 'CMD_HELP' and UI_mode != 'json':
|
||||
sys.stdout.write('\n%s\n' % helptext)
|
||||
ans = 'again'
|
||||
|
602
apparmor-yast-cleanup.patch
Normal file
602
apparmor-yast-cleanup.patch
Normal file
@ -0,0 +1,602 @@
|
||||
commit 99e2b9e1dfccf765dd84f44f1368892b6a082406
|
||||
Author: Goldwyn Rodrigues <rgoldwyn@suse.com>
|
||||
Date: Sun Jun 11 13:03:44 2017 +0200
|
||||
|
||||
Remove yast from utils
|
||||
|
||||
From: Goldwyn Rodrigues <rgoldwyn@suse.com>
|
||||
|
||||
This is the yast cleanup from the utils code. All yast communication
|
||||
should be done with JSON interface now.
|
||||
|
||||
Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
|
||||
|
||||
|
||||
|
||||
Acked-by: Christian Boltz <apparmor@cboltz.de>
|
||||
|
||||
diff --git a/utils/apparmor/aa.py b/utils/apparmor/aa.py
|
||||
index 141c20dd..6db4b277 100644
|
||||
--- a/utils/apparmor/aa.py
|
||||
+++ b/utils/apparmor/aa.py
|
||||
@@ -14,7 +14,6 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# No old version logs, only 2.6 + supported
|
||||
from __future__ import division, with_statement
|
||||
-import inspect
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
@@ -64,8 +63,6 @@ from apparmor.rule import quote_if_needed
|
||||
|
||||
ruletypes = ['capability', 'change_profile', 'dbus', 'file', 'network', 'ptrace', 'rlimit', 'signal']
|
||||
|
||||
-from apparmor.yasti import SendDataToYast, GetDataFromYast, shutdown_yast
|
||||
-
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
@@ -146,15 +143,9 @@ def fatal_error(message):
|
||||
# Add the traceback to message
|
||||
message = tb_stack + '\n\n' + message
|
||||
debug_logger.error(message)
|
||||
- caller = inspect.stack()[1][3]
|
||||
-
|
||||
- # If caller is SendDataToYast or GetDatFromYast simply exit
|
||||
- if caller == 'SendDataToYast' or caller == 'GetDatFromYast':
|
||||
- sys.exit(1)
|
||||
|
||||
# Else tell user what happened
|
||||
aaui.UI_Important(message)
|
||||
- shutdown_yast()
|
||||
sys.exit(1)
|
||||
|
||||
def check_for_apparmor(filesystem='/proc/filesystems', mounts='/proc/mounts'):
|
||||
@@ -539,7 +530,6 @@ def confirm_and_abort():
|
||||
ans = aaui.UI_YesNo(_('Are you sure you want to abandon this set of profile changes and exit?'), 'n')
|
||||
if ans == 'y':
|
||||
aaui.UI_Info(_('Abandoning all changes.'))
|
||||
- shutdown_yast()
|
||||
for prof in created:
|
||||
delete_profile(prof)
|
||||
sys.exit(0)
|
||||
@@ -601,20 +591,12 @@ def get_profile(prof_name):
|
||||
p = profile_hash[options[arg]]
|
||||
q.selected = options.index(options[arg])
|
||||
if ans == 'CMD_VIEW_PROFILE':
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- SendDataToYast({'type': 'dialogue-view-profile',
|
||||
- 'user': options[arg],
|
||||
- 'profile': p['profile'],
|
||||
- 'profile_type': p['profile_type']
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
- else:
|
||||
- pager = get_pager()
|
||||
- proc = subprocess.Popen(pager, stdin=subprocess.PIPE)
|
||||
+ pager = get_pager()
|
||||
+ proc = subprocess.Popen(pager, stdin=subprocess.PIPE)
|
||||
# proc.communicate('Profile submitted by %s:\n\n%s\n\n' %
|
||||
# (options[arg], p['profile']))
|
||||
- proc.communicate(p['profile'].encode())
|
||||
- proc.kill()
|
||||
+ proc.communicate(p['profile'].encode())
|
||||
+ proc.kill()
|
||||
elif ans == 'CMD_USE_PROFILE':
|
||||
if p['profile_type'] == 'INACTIVE_LOCAL':
|
||||
profile_data = p['profile_data']
|
||||
@@ -864,76 +846,16 @@ def fetch_profiles_by_user(url, distro, user):
|
||||
def submit_created_profiles(new_profiles):
|
||||
#url = cfg['repository']['url']
|
||||
if new_profiles:
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- 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)
|
||||
+ 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:
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- 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.\nWould 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])
|
||||
- SendDataToYast({'type': 'dialog-select-profiles',
|
||||
- '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'
|
||||
- aaui.UI_Important(_('WARNING: An error occurred while uploading the profile %(profile)s\n%(ret)s') % { 'profile': p, 'ret': ret })
|
||||
- aaui.UI_Info(_('Uploaded changes to repository.'))
|
||||
- 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)
|
||||
+ title = 'Submit changed profiles to the repository'
|
||||
+ message = 'The following profiles from the repository were changed.\nWould you like to upload your changes?'
|
||||
+ console_select_and_upload_profiles(title, message, changed_profiles)
|
||||
|
||||
def upload_profile(url, user, passw, distro, p, profile_string, changelog):
|
||||
# To-Do
|
||||
@@ -1925,10 +1847,6 @@ def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
|
||||
|
||||
ask_the_questions(log_dict)
|
||||
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- # To-Do
|
||||
- pass
|
||||
-
|
||||
finishing = False
|
||||
# Check for finished
|
||||
save_profiles()
|
||||
@@ -1958,78 +1876,50 @@ def save_profiles():
|
||||
changed_list = sorted(changed.keys())
|
||||
|
||||
if changed_list:
|
||||
+ q = aaui.PromptQuestion()
|
||||
+ q.title = 'Changed Local Profiles'
|
||||
+ q.explanation = _('The following local profiles were changed. Would you like to save them?')
|
||||
+ q.functions = ['CMD_SAVE_CHANGES', 'CMD_SAVE_SELECTED', 'CMD_VIEW_CHANGES', 'CMD_VIEW_CHANGES_CLEAN', 'CMD_ABORT']
|
||||
+ q.default = 'CMD_VIEW_CHANGES'
|
||||
+ q.options = changed
|
||||
+ q.selected = 0
|
||||
+ ans = ''
|
||||
+ arg = None
|
||||
+ while ans != 'CMD_SAVE_CHANGES':
|
||||
+ if not changed:
|
||||
+ return
|
||||
+ ans, arg = q.promptUser()
|
||||
+ if ans == 'CMD_SAVE_SELECTED':
|
||||
+ profile_name = list(changed.keys())[arg]
|
||||
+ write_profile_ui_feedback(profile_name)
|
||||
+ reload_base(profile_name)
|
||||
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- # To-Do
|
||||
- # selected_profiles = [] # XXX selected_profiles_ref?
|
||||
- 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)
|
||||
- explanation = _('Select which profile changes you would like to save to the\nlocal profile set.')
|
||||
- title = _('Local profile changes')
|
||||
- SendDataToYast({'type': 'dialog-select-profiles',
|
||||
- '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:
|
||||
- write_profile_ui_feedback(profile_name)
|
||||
- reload_base(profile_name)
|
||||
-
|
||||
- else:
|
||||
- q = aaui.PromptQuestion()
|
||||
- q.title = 'Changed Local Profiles'
|
||||
- q.explanation = _('The following local profiles were changed. Would you like to save them?')
|
||||
- q.functions = ['CMD_SAVE_CHANGES', 'CMD_SAVE_SELECTED', 'CMD_VIEW_CHANGES', 'CMD_VIEW_CHANGES_CLEAN', 'CMD_ABORT']
|
||||
- q.default = 'CMD_VIEW_CHANGES'
|
||||
- q.options = changed
|
||||
- q.selected = 0
|
||||
- ans = ''
|
||||
- arg = None
|
||||
- while ans != 'CMD_SAVE_CHANGES':
|
||||
- if not changed:
|
||||
- return
|
||||
- ans, arg = q.promptUser()
|
||||
- if ans == 'CMD_SAVE_SELECTED':
|
||||
- profile_name = list(changed.keys())[arg]
|
||||
- write_profile_ui_feedback(profile_name)
|
||||
- reload_base(profile_name)
|
||||
-
|
||||
- elif ans == 'CMD_VIEW_CHANGES':
|
||||
- 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)
|
||||
+ elif ans == 'CMD_VIEW_CHANGES':
|
||||
+ 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)
|
||||
|
||||
- try:
|
||||
- newprofile = serialize_profile_from_old_profile(aa[which], which, '')
|
||||
- except AttributeError:
|
||||
- # see https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1528139
|
||||
- newprofile = "###\n###\n### Internal error while generating diff, please use '%s' instead\n###\n###\n" % _('View Changes b/w (C)lean profiles')
|
||||
+ try:
|
||||
+ newprofile = serialize_profile_from_old_profile(aa[which], which, '')
|
||||
+ except AttributeError:
|
||||
+ # see https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1528139
|
||||
+ newprofile = "###\n###\n### Internal error while generating diff, please use '%s' instead\n###\n###\n" % _('View Changes b/w (C)lean profiles')
|
||||
|
||||
- display_changes_with_comments(oldprofile, newprofile)
|
||||
+ display_changes_with_comments(oldprofile, newprofile)
|
||||
|
||||
- elif ans == 'CMD_VIEW_CHANGES_CLEAN':
|
||||
- which = list(changed.keys())[arg]
|
||||
- oldprofile = serialize_profile(original_aa[which], which, '')
|
||||
- newprofile = serialize_profile(aa[which], which, '')
|
||||
+ elif ans == 'CMD_VIEW_CHANGES_CLEAN':
|
||||
+ which = list(changed.keys())[arg]
|
||||
+ oldprofile = serialize_profile(original_aa[which], which, '')
|
||||
+ newprofile = serialize_profile(aa[which], which, '')
|
||||
|
||||
- display_changes(oldprofile, newprofile)
|
||||
+ display_changes(oldprofile, newprofile)
|
||||
|
||||
- for profile_name in sorted(changed.keys()):
|
||||
- write_profile_ui_feedback(profile_name)
|
||||
- reload_base(profile_name)
|
||||
+ for profile_name in sorted(changed.keys()):
|
||||
+ write_profile_ui_feedback(profile_name)
|
||||
+ reload_base(profile_name)
|
||||
|
||||
def get_pager():
|
||||
return 'less'
|
||||
@@ -2065,33 +1955,26 @@ def get_profile_diff(oldprofile, newprofile):
|
||||
return ''.join(diff)
|
||||
|
||||
def display_changes(oldprofile, newprofile):
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- aaui.UI_LongMessage(_('Profile Changes'), get_profile_diff(oldprofile, newprofile))
|
||||
- else:
|
||||
- difftemp = generate_diff(oldprofile, newprofile)
|
||||
- subprocess.call('less %s' % difftemp.name, shell=True)
|
||||
- difftemp.delete = True
|
||||
- difftemp.close()
|
||||
+ difftemp = generate_diff(oldprofile, newprofile)
|
||||
+ subprocess.call('less %s' % difftemp.name, shell=True)
|
||||
+ difftemp.delete = True
|
||||
+ difftemp.close()
|
||||
|
||||
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):
|
||||
raise AppArmorException(_("Can't find existing profile %s to compare changes.") % oldprofile)
|
||||
- if aaui.UI_mode == 'yast':
|
||||
- #To-Do
|
||||
- pass
|
||||
- else:
|
||||
- newtemp = tempfile.NamedTemporaryFile('w')
|
||||
- newtemp.write(newprofile)
|
||||
- newtemp.flush()
|
||||
+ newtemp = tempfile.NamedTemporaryFile('w')
|
||||
+ newtemp.write(newprofile)
|
||||
+ newtemp.flush()
|
||||
|
||||
- difftemp = tempfile.NamedTemporaryFile('w')
|
||||
+ difftemp = tempfile.NamedTemporaryFile('w')
|
||||
|
||||
- subprocess.call('diff -u -p %s %s > %s' % (oldprofile, newtemp.name, difftemp.name), shell=True)
|
||||
+ subprocess.call('diff -u -p %s %s > %s' % (oldprofile, newtemp.name, difftemp.name), shell=True)
|
||||
|
||||
- newtemp.close()
|
||||
- subprocess.call('less %s' % difftemp.name, shell=True)
|
||||
- difftemp.close()
|
||||
+ newtemp.close()
|
||||
+ subprocess.call('less %s' % difftemp.name, shell=True)
|
||||
+ difftemp.close()
|
||||
|
||||
def set_process(pid, profile):
|
||||
# If process not running don't do anything
|
||||
diff --git a/utils/apparmor/ui.py b/utils/apparmor/ui.py
|
||||
index bfbde8c6..f25fff31 100644
|
||||
--- a/utils/apparmor/ui.py
|
||||
+++ b/utils/apparmor/ui.py
|
||||
@@ -14,7 +14,6 @@
|
||||
import sys
|
||||
import re
|
||||
import readline
|
||||
-from apparmor.yasti import yastLog, SendDataToYast, GetDataFromYast
|
||||
|
||||
from apparmor.common import readkey, AppArmorException, DebugLogger
|
||||
|
||||
@@ -47,18 +46,11 @@ def UI_Info(text):
|
||||
debug_logger.info(text)
|
||||
if UI_mode == 'text':
|
||||
sys.stdout.write(text + '\n')
|
||||
- else:
|
||||
- yastLog(text)
|
||||
|
||||
def UI_Important(text):
|
||||
debug_logger.debug(text)
|
||||
if UI_mode == 'text':
|
||||
sys.stdout.write('\n' + text + '\n')
|
||||
- else:
|
||||
- SendDataToYast({'type': 'dialog-error',
|
||||
- 'message': text
|
||||
- })
|
||||
- path, yarg = GetDataFromYast()
|
||||
|
||||
def get_translated_hotkey(translated, cmsg=''):
|
||||
msg = 'PromptUser: ' + _('Invalid hotkey for')
|
||||
@@ -105,15 +97,6 @@ def UI_YesNo(text, default):
|
||||
continue # If user presses any other button ask again
|
||||
else:
|
||||
ans = default
|
||||
-
|
||||
- else:
|
||||
- SendDataToYast({'type': 'dialog-yesno',
|
||||
- 'question': text
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
- ans = yarg['answer']
|
||||
- if not ans:
|
||||
- ans = default
|
||||
return ans
|
||||
|
||||
def UI_YesNoCancel(text, default):
|
||||
@@ -160,14 +143,6 @@ def UI_YesNoCancel(text, default):
|
||||
default = 'c'
|
||||
else:
|
||||
ans = default
|
||||
- else:
|
||||
- SendDataToYast({'type': 'dialog-yesnocancel',
|
||||
- 'question': text
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
- ans = yarg['answer']
|
||||
- if not ans:
|
||||
- ans = default
|
||||
return ans
|
||||
|
||||
def UI_GetString(text, default):
|
||||
@@ -181,13 +156,6 @@ def UI_GetString(text, default):
|
||||
string = ''
|
||||
finally:
|
||||
readline.set_startup_hook()
|
||||
- else:
|
||||
- SendDataToYast({'type': 'dialog-getstring',
|
||||
- 'label': text,
|
||||
- 'default': default
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
- string = yarg['string']
|
||||
return string.strip()
|
||||
|
||||
def UI_GetFile(file):
|
||||
@@ -196,29 +164,15 @@ def UI_GetFile(file):
|
||||
if UI_mode == 'text':
|
||||
sys.stdout.write(file['description'] + '\n')
|
||||
filename = sys.stdin.read()
|
||||
- else:
|
||||
- file['type'] = 'dialog-getfile'
|
||||
- SendDataToYast(file)
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
- if yarg['answer'] == 'okay':
|
||||
- filename = yarg['filename']
|
||||
return filename
|
||||
|
||||
def UI_BusyStart(message):
|
||||
debug_logger.debug('UI_BusyStart: %s' % UI_mode)
|
||||
if UI_mode == 'text':
|
||||
UI_Info(message)
|
||||
- else:
|
||||
- SendDataToYast({'type': 'dialog-busy-start',
|
||||
- 'message': message
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
|
||||
def UI_BusyStop():
|
||||
debug_logger.debug('UI_BusyStop: %s' % UI_mode)
|
||||
- if UI_mode != 'text':
|
||||
- SendDataToYast({'type': 'dialog-busy-stop'})
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
|
||||
CMDS = {'CMD_ALLOW': _('(A)llow'),
|
||||
'CMD_OTHER': _('(M)ore'),
|
||||
@@ -302,13 +256,6 @@ class PromptQuestion(object):
|
||||
arg = None
|
||||
if UI_mode == 'text':
|
||||
cmd, arg = self.Text_PromptUser()
|
||||
- else:
|
||||
- self.type = 'wizard'
|
||||
- SendDataToYast(self)
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
- if not cmd:
|
||||
- cmd = 'CMD_ABORT'
|
||||
- arg = yarg['selected']
|
||||
if cmd == 'CMD_ABORT':
|
||||
confirm_and_abort()
|
||||
cmd = 'XXXINVALIDXXX'
|
||||
@@ -447,25 +394,8 @@ def confirm_and_abort():
|
||||
ans = UI_YesNo(_('Are you sure you want to abandon this set of profile changes and exit?'), 'n')
|
||||
if ans == 'y':
|
||||
UI_Info(_('Abandoning all changes.'))
|
||||
- #shutdown_yast()
|
||||
- #for prof in created:
|
||||
- # delete_profile(prof)
|
||||
sys.exit(0)
|
||||
|
||||
-def UI_ShortMessage(title, message):
|
||||
- SendDataToYast({'type': 'short-dialog-message',
|
||||
- 'headline': title,
|
||||
- 'message': message
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
-
|
||||
-def UI_LongMessage(title, message):
|
||||
- SendDataToYast({'type': 'long-dialog-message',
|
||||
- 'headline': title,
|
||||
- 'message': message
|
||||
- })
|
||||
- ypath, yarg = GetDataFromYast()
|
||||
-
|
||||
def is_number(number):
|
||||
try:
|
||||
return int(number)
|
||||
diff --git a/utils/apparmor/yasti.py b/utils/apparmor/yasti.py
|
||||
deleted file mode 100644
|
||||
index 180e7152..00000000
|
||||
--- a/utils/apparmor/yasti.py
|
||||
+++ /dev/null
|
||||
@@ -1,106 +0,0 @@
|
||||
-# ----------------------------------------------------------------------
|
||||
-# 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.
|
||||
-#
|
||||
-# ----------------------------------------------------------------------
|
||||
-import re
|
||||
-import sys
|
||||
-try:
|
||||
- import ycp
|
||||
-except ImportError:
|
||||
- # ycp isn't found everywhere.
|
||||
- ycp = None
|
||||
-
|
||||
-from apparmor.common import error, DebugLogger
|
||||
-
|
||||
-# Set up UI logger for separate messages from YaST module
|
||||
-debug_logger = DebugLogger('YaST')
|
||||
-
|
||||
-
|
||||
-def setup_yast():
|
||||
- # To-Do
|
||||
- pass
|
||||
-
|
||||
-def shutdown_yast():
|
||||
- # To-Do
|
||||
- pass
|
||||
-
|
||||
-def yastLog(text):
|
||||
- ycp.y2milestone(text)
|
||||
-
|
||||
-def SendDataToYast(data):
|
||||
- debug_logger.info('SendDataToYast: Waiting for YCP command')
|
||||
- for line in sys.stdin:
|
||||
- ycommand, ypath, yargument = ParseCommand(line)
|
||||
- if ycommand and ycommand == 'Read':
|
||||
- debug_logger.info('SendDataToYast: Sending--%s' % data)
|
||||
- ycp.Return(data)
|
||||
- return True
|
||||
- else:
|
||||
- debug_logger.info('SendDataToYast: Expected \'Read\' but got-- %s' % line)
|
||||
- error('SendDataToYast: didn\'t receive YCP command before connection died')
|
||||
-
|
||||
-def GetDataFromYast():
|
||||
- debug_logger.inf('GetDataFromYast: Waiting for YCP command')
|
||||
- for line in sys.stdin:
|
||||
- debug_logger.info('GetDataFromYast: YCP: %s' % line)
|
||||
- ycommand, ypath, yarg = ParseCommand(line)
|
||||
- debug_logger.info('GetDataFromYast: Recieved--\n%s' % yarg)
|
||||
- if ycommand and ycommand == 'Write':
|
||||
- ycp.Return('true')
|
||||
- return ypath, yarg
|
||||
- else:
|
||||
- debug_logger.info('GetDataFromYast: Expected Write but got-- %s' % line)
|
||||
- error('GetDataFromYast: didn\'t receive YCP command before connection died')
|
||||
-
|
||||
-def ParseCommand(commands):
|
||||
- term = ParseTerm(commands)
|
||||
- if term:
|
||||
- command = term[0]
|
||||
- term = term[1:]
|
||||
- else:
|
||||
- command = ''
|
||||
- path = ''
|
||||
- pathref = None
|
||||
- if term:
|
||||
- pathref = term[0]
|
||||
- term = term[1:]
|
||||
- if pathref:
|
||||
- if pathref.strip():
|
||||
- path = pathref.strip()
|
||||
- elif command != 'result':
|
||||
- ycp.y2error('The first arguement is not a path. (%s)' % pathref)
|
||||
- argument = None
|
||||
- if term:
|
||||
- argument = term[0]
|
||||
- if len(term) > 1:
|
||||
- ycp.y2warning('Superfluous command arguments ignored')
|
||||
- return (command, path, argument)
|
||||
-
|
||||
-def ParseTerm(inp):
|
||||
- regex_term = re.compile('^\s*`?(\w*)\s*')
|
||||
- term = regex_term.search(inp)
|
||||
- ret = []
|
||||
- symbol = None
|
||||
- if term:
|
||||
- symbol = term.groups()[0]
|
||||
- else:
|
||||
- ycp.y2error('No term symbol')
|
||||
- ret.append(symbol)
|
||||
- inp = regex_term.sub('', inp)
|
||||
- if not inp.startswith('('):
|
||||
- ycp.y2error('No term parantheses')
|
||||
- argref, err, rest = ycp.ParseYcpTermBody(inp)
|
||||
- if err:
|
||||
- ycp.y2error('%s (%s)' % (err, rest))
|
||||
- else:
|
||||
- ret += argref
|
||||
- return ret
|
@ -1,3 +1,14 @@
|
||||
-------------------------------------------------------------------
|
||||
Fri Jul 14 18:51:26 UTC 2017 - suse-beta@cboltz.de
|
||||
|
||||
- don't rely on implementation details for reload in %post
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Jul 12 13:33:20 UTC 2017 - rgoldwyn@suse.com
|
||||
|
||||
- add JSON support. Required for FATE#323380.
|
||||
(apparmor-yast-cleanup.patch, apparmor-json-support.patch)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sat Mar 25 21:42:10 UTC 2017 - suse-beta@cboltz.de
|
||||
|
||||
|
@ -81,6 +81,10 @@ Patch10: upstream-changes-r3629..3648.diff
|
||||
# add some exceptions to utils/test/test-parser-simple-tests.py (submitted upstream 2017-03-25)
|
||||
Patch11: parser-tests-dbus-duplicated-conditionals.diff
|
||||
|
||||
# add JSON support to aa-logprof and aa-genprof (will be in upstream 2.12)
|
||||
Patch12: apparmor-yast-cleanup.patch
|
||||
Patch13: apparmor-json-support.patch
|
||||
|
||||
PreReq: sed
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
%define apparmor_bin_prefix /lib/apparmor
|
||||
@ -384,6 +388,8 @@ SubDomain.
|
||||
# patch10 (upstream-changes-r3629..3648.diff) fails to create empty files, do it manually
|
||||
touch libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.err
|
||||
%patch11
|
||||
%patch12 -p1
|
||||
%patch13 -p1
|
||||
|
||||
# search for left-over multiline rules
|
||||
test -z "$(grep -r '^\s*\(unix\|dbus\)[^,]\(([^)]*)\)*[^,]*$' profiles/apparmor.d/)"
|
||||
@ -737,14 +743,14 @@ export DISABLE_RESTART_ON_UPDATE="yes"
|
||||
%service_del_postun apparmor.service
|
||||
|
||||
%post abstractions
|
||||
#restart_on_update boot.apparmor - but non-broken (bnc#853019)
|
||||
systemctl is-active -q apparmor && /lib/apparmor/apparmor.systemd reload ||:
|
||||
#restart_on_update apparmor - but non-broken (bnc#853019)
|
||||
systemctl is-active -q apparmor && systemctl reload apparmor ||:
|
||||
|
||||
%post profiles
|
||||
# workaround for bnc#904620#c8 / lp#1392042
|
||||
rm -f /var/lib/apparmor/cache/* 2>/dev/null
|
||||
#restart_on_update boot.apparmor - but non-broken (bnc#853019)
|
||||
systemctl is-active -q apparmor && /lib/apparmor/apparmor.systemd reload ||:
|
||||
#restart_on_update apparmor - but non-broken (bnc#853019)
|
||||
systemctl is-active -q apparmor && systemctl reload apparmor ||:
|
||||
|
||||
%if %{with tomcat}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user