2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 18:17:09 +00:00
2013-09-20 19:20:41 +05:30

431 lines
14 KiB
Python

# 1728
import sys
import os
import re
from apparmor.yasti import yastLog, SendDataToYast, GetDataFromYast
from apparmor.common import readkey, AppArmorException, DebugLogger, msg
# 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'
ARROWS = {'A': 'UP', 'B': 'DOWN', 'C': 'RIGHT', 'D': 'LEFT'}
def getkey():
key = readkey()
if key == '\x1B':
key = readkey()
if key == '[':
key = readkey()
if(ARROWS.get(key, False)):
key = ARROWS[key]
return key
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')
if re.search('\((\S)\)', translated):
return re.search('\((\S)\)', translated).groups()[0]
else:
if cmsg:
raise AppArmorException(cmsg)
else:
raise AppArmorException('%s %s' %(msg, translated))
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 = _('(Y)es')
no = _('(N)o')
yeskey = get_translated_hotkey(yes).lower()
nokey = get_translated_hotkey(no).lower()
ans = 'XXXINVALIDXXX'
while ans not in ['y', 'n']:
sys.stdout.write('\n' + text + '\n')
if default == 'y':
sys.stdout.write('\n[%s] / %s\n' % (yes, no))
else:
sys.stdout.write('\n%s / [%s]\n' % (yes, no))
ans = getkey()
if ans:
# Get back to english from localised answer
ans = ans.lower()
if ans == yeskey:
ans = 'y'
else:
ans = 'n'
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):
debug_logger.debug('UI_YesNoCancel: %s: %s %s' % (UI_mode, text, default))
default = default.lower()
ans = None
if UI_mode == 'text':
yes = _('(Y)es')
no = _('(N)o')
cancel = _('(C)ancel')
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']:
sys.stdout.write('\n' + text + '\n')
if default == 'y':
sys.stdout.write('\n[%s] / %s / %s\n' % (yes, no, cancel))
elif default == 'n':
sys.stdout.write('\n%s / [%s] / %s\n' % (yes, no, cancel))
else:
sys.stdout.write('\n%s / %s / [%s]\n' % (yes, no, cancel))
ans = getkey()
if ans:
# Get back to english from localised answer
ans = ans.lower()
if ans == yeskey:
ans = 'y'
elif ans == nokey:
ans = 'n'
elif ans== cancelkey:
ans= '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):
debug_logger.debug('UI_GetString: %s: %s %s' % (UI_mode, text, default))
string = default
if UI_mode == 'text':
sys.stdout.write('\n' + text)
string = sys.stdin.readline()
else:
SendDataToYast({
'type': 'dialog-getstring',
'label': text,
'default': default
})
ypath, yarg = GetDataFromYast()
string = yarg['string']
return string.strip()
def UI_GetFile(file):
debug_logger.debug('UI_GetFile: %s' % UI_mode)
filename = None
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'),
'CMD_AUDIT_NEW': _('Audi(t)'),
'CMD_AUDIT_OFF': _('Audi(t) off'),
'CMD_AUDIT_FULL': _('Audit (A)ll'),
#'CMD_OTHER': '(O)pts',
'CMD_USER_ON': _('(O)wner permissions on'),
'CMD_USER_OFF': _('(O)wner permissions off'),
'CMD_DENY': _('(D)eny'),
'CMD_ABORT': _('Abo(r)t'),
'CMD_FINISHED': _('(F)inish'),
'CMD_ix': _('(I)nherit'),
'CMD_px': _('(P)rofile'),
'CMD_px_safe': _('(P)rofile Clean Exec'),
'CMD_cx': _('(C)hild'),
'CMD_cx_safe': _('(C)hild Clean Exec'),
'CMD_nx': _('Named'),
'CMD_nx_safe': _('Named Clean Exec'),
'CMD_ux': _('(U)nconfined'),
'CMD_ux_safe': _('(U)nconfined Clean Exec'),
'CMD_pix': _('(P)rofile Inherit'),
'CMD_pix_safe': _('(P)rofile Inherit Clean Exec'),
'CMD_cix': _('(C)hild Inherit'),
'CMD_cix_safe': _('(C)hild Inherit Clean Exec'),
'CMD_nix': _('(N)amed Inherit'),
'CMD_nix_safe': _('(N)amed Inherit Clean Exec'),
'CMD_EXEC_IX_ON': _('(X) ix On'),
'CMD_EXEC_IX_OFF': _('(X) ix Off'),
'CMD_SAVE': _('(S)ave Changes'),
'CMD_CONTINUE': _('(C)ontinue Profiling'),
'CMD_NEW': _('(N)ew'),
'CMD_GLOB': _('(G)lob'),
'CMD_GLOBEXT': _('Glob with (E)xtension'),
'CMD_ADDHAT': _('(A)dd Requested Hat'),
'CMD_USEDEFAULT': _('(U)se Default Hat'),
'CMD_SCAN': _('(S)can system log for AppArmor events'),
'CMD_HELP': _('(H)elp'),
'CMD_VIEW_PROFILE': _('(V)iew Profile'),
'CMD_USE_PROFILE': _('(U)se Profile'),
'CMD_CREATE_PROFILE': _('(C)reate New Profile'),
'CMD_UPDATE_PROFILE': _('(U)pdate Profile'),
'CMD_IGNORE_UPDATE': _('(I)gnore Update'),
'CMD_SAVE_CHANGES': _('(S)ave Changes'),
'CMD_SAVE_SELECTED': _('Save Selec(t)ed Profile'),
'CMD_UPLOAD_CHANGES': _('(U)pload Changes'),
'CMD_VIEW_CHANGES': _('(V)iew Changes'),
'CMD_VIEW_CHANGES_CLEAN': _('View Changes b/w (C)lean profiles'),
'CMD_VIEW': _('(V)iew'),
'CMD_ENABLE_REPO': _('(E)nable Repository'),
'CMD_DISABLE_REPO': _('(D)isable Repository'),
'CMD_ASK_NEVER': _('(N)ever Ask Again'),
'CMD_ASK_LATER': _('Ask Me (L)ater'),
'CMD_YES': _('(Y)es'),
'CMD_NO': _('(N)o'),
'CMD_ALL_NET': _('Allow All (N)etwork'),
'CMD_NET_FAMILY': _('Allow Network Fa(m)ily'),
'CMD_OVERWRITE': _('(O)verwrite Profile'),
'CMD_KEEP': _('(K)eep Profile'),
'CMD_CONTINUE': _('(C)ontinue'),
'CMD_IGNORE_ENTRY': _('(I)gnore')
}
def UI_PromptUser(q, params=''):
cmd = None
arg = None
if UI_mode == 'text':
cmd, arg = Text_PromptUser(q)
else:
q['type'] = 'wizard'
SendDataToYast(q)
ypath, yarg = GetDataFromYast()
if not cmd:
cmd = 'CMD_ABORT'
arg = yarg['selected']
if cmd == 'CMD_ABORT':
confirm_and_abort()
cmd = 'XXXINVALIDXXX'
elif cmd == 'CMD_FINISHED':
if not params:
confirm_and_finish()
cmd = 'XXXINVALIDXXX'
return (cmd, arg)
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 confirm_and_finish():
sys.stdout.write(_('FINISHING...\n'))
sys.exit(0)
def Text_PromptUser(question):
title = question['title']
explanation = question['explanation']
headers = question['headers']
functions = question['functions']
default = question['default']
options = question['options']
selected = question.get('selected', 0)
helptext = question['helptext']
if helptext:
functions.append('CMD_HELP')
menu_items = []
keys = dict()
for cmd in functions:
if not CMDS.get(cmd, False):
raise AppArmorException(_('PromptUser: Unknown command %s') % cmd)
menutext = CMDS[cmd]
key = get_translated_hotkey(menutext).lower()
# Duplicate hotkey
if keys.get(key, False):
raise AppArmorException(_('PromptUser: Duplicate hotkey for %s: %s ') % (cmd, menutext))
keys[key] = cmd
if default and default == cmd:
menutext = '[%s]' %menutext
menu_items.append(menutext)
default_key = 0
if default and CMDS[default]:
defaulttext = CMDS[default]
defmsg = _('PromptUser: Invalid hotkey in default item')
default_key = get_translated_hotkey(defaulttext, defmsg).lower()
if not keys.get(default_key, False):
raise AppArmorException(_('PromptUser: Invalid default %s') % default)
widest = 0
header_copy = headers[:]
while header_copy:
header = header_copy.pop(0)
header_copy.pop(0)
if len(header) > widest:
widest = len(header)
widest += 1
formatstr = '%-' + str(widest) + 's %s\n'
function_regexp = '^('
function_regexp += '|'.join(keys.keys())
if options:
function_regexp += '|\d'
function_regexp += ')$'
ans = 'XXXINVALIDXXX'
while not re.search(function_regexp, ans, flags=re.IGNORECASE):
prompt = '\n'
if title:
prompt += '= %s =\n\n' %title
if headers:
header_copy = headers[:]
while header_copy:
header = header_copy.pop(0)
value = header_copy.pop(0)
prompt += formatstr %(header+':', value)
prompt += '\n'
if explanation:
prompt += explanation + '\n\n'
if options:
for index, option in enumerate(options):
if selected == index:
format_option = ' [%s - %s]'
else:
format_option = ' %s - %s '
prompt += format_option %(index+1, option)
prompt += '\n'
prompt += ' / '.join(menu_items)
sys.stdout.write(prompt+'\n')
ans = getkey().lower()
if ans:
if ans == 'up':
if options and selected > 0:
selected -= 1
ans = 'XXXINVALIDXXX'
elif ans == 'down':
if options and selected < len(options)-1:
selected += 1
ans = 'XXXINVALIDXXX'
# elif keys.get(ans, False) == 'CMD_HELP':
# sys.stdout.write('\n%s\n' %helptext)
# ans = 'XXXINVALIDXXX'
elif is_number(ans) == 10:
# If they hit return choose default option
ans = default_key
elif options and re.search('^\d$', ans):
ans = int(ans)
if ans > 0 and ans <= len(options):
selected = ans - 1
ans = 'XXXINVALIDXXX'
if keys.get(ans, False) == 'CMD_HELP':
sys.stdout.write('\n%s\n' %helptext)
ans = 'again'
if keys.get(ans, False):
ans = keys[ans]
return ans, selected
def is_number(number):
try:
return int(number)
except:
return False