mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-20 11:48:43 -06:00
Move setting SELinux booleans to platform code
Create a platform task for setting SELinux booleans. Use an exception for the case when the booleans could not be set (since this is an error if not handled). Since ipaplatform should not depend on ipalib, create a new errors module in ipapython for SetseboolError. Handle uninstallation with the same task, which means the booleans are now restored with a single call to setsebool. Preparation for: https://fedorahosted.org/freeipa/ticket/4157 Fixes: https://fedorahosted.org/freeipa/ticket/2934 Fixes: https://fedorahosted.org/freeipa/ticket/2519 Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
This commit is contained in:
parent
757272a3f8
commit
c7d6fea06f
@ -132,4 +132,23 @@ class BaseTaskNamespace(object):
|
||||
|
||||
return
|
||||
|
||||
def set_selinux_booleans(self, required_settings, backup_func=None):
|
||||
"""Set the specified SELinux booleans
|
||||
|
||||
:param required_settings: A dictionary mapping the boolean names
|
||||
to desired_values.
|
||||
The desired value can be 'on' or 'off'.
|
||||
|
||||
:param backup_func: A function called for each boolean with two
|
||||
arguments: the name and the previous value
|
||||
|
||||
If SELinux is disabled, return False; on success returns True.
|
||||
|
||||
If setting the booleans fails,
|
||||
an ipapython.errors.SetseboolError is raised.
|
||||
"""
|
||||
|
||||
return
|
||||
|
||||
|
||||
task_namespace = BaseTaskNamespace()
|
||||
|
@ -24,7 +24,6 @@ This module contains default Fedora-specific implementations of system tasks.
|
||||
'''
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import socket
|
||||
import sys
|
||||
@ -35,8 +34,9 @@ from subprocess import CalledProcessError
|
||||
from nss.error import NSPRError
|
||||
from pyasn1.error import PyAsn1Error
|
||||
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
from ipapython.ipa_log_manager import root_logger, log_mgr
|
||||
from ipapython import ipautil
|
||||
import ipapython.errors
|
||||
|
||||
from ipalib import x509 # FIXME: do not import from ipalib
|
||||
|
||||
@ -45,6 +45,9 @@ from ipaplatform.fedora.authconfig import FedoraAuthConfig
|
||||
from ipaplatform.base.tasks import BaseTaskNamespace
|
||||
|
||||
|
||||
log = log_mgr.get_logger(__name__)
|
||||
|
||||
|
||||
class FedoraTaskNamespace(BaseTaskNamespace):
|
||||
|
||||
def restore_context(self, filepath, restorecon=paths.SBIN_RESTORECON):
|
||||
@ -326,4 +329,50 @@ class FedoraTaskNamespace(BaseTaskNamespace):
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def set_selinux_booleans(self, required_settings, backup_func=None):
|
||||
def get_setsebool_args(changes):
|
||||
args = [paths.SETSEBOOL, "-P"]
|
||||
args.extend(["%s=%s" % update for update in changes.iteritems()])
|
||||
|
||||
return args
|
||||
|
||||
if (os.path.exists(paths.SELINUXENABLED)):
|
||||
try:
|
||||
ipautil.run([paths.SELINUXENABLED])
|
||||
except ipautil.CalledProcessError:
|
||||
# selinuxenabled returns 1 if not enabled
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
updated_vars = {}
|
||||
failed_vars = {}
|
||||
for setting, state in required_settings.iteritems():
|
||||
try:
|
||||
(stdout, stderr, rc) = ipautil.run([paths.GETSEBOOL, setting])
|
||||
original_state = stdout.split()[2]
|
||||
if backup_func is not None:
|
||||
backup_func(setting, original_state)
|
||||
|
||||
if original_state != state:
|
||||
updated_vars[setting] = state
|
||||
except ipautil.CalledProcessError, e:
|
||||
log.error("Cannot get SELinux boolean '%s': %s", setting, e)
|
||||
failed_vars[setting] = state
|
||||
|
||||
if updated_vars:
|
||||
args = get_setsebool_args(updated_vars)
|
||||
try:
|
||||
ipautil.run(args)
|
||||
except ipautil.CalledProcessError:
|
||||
failed_vars.update(updated_vars)
|
||||
|
||||
if failed_vars:
|
||||
raise ipapython.errors.SetseboolError(
|
||||
failed=failed_vars,
|
||||
command=' '.join(get_setsebool_args(failed_vars)))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
tasks = FedoraTaskNamespace()
|
||||
|
47
ipapython/errors.py
Normal file
47
ipapython/errors.py
Normal file
@ -0,0 +1,47 @@
|
||||
# Authors: Petr Viktorin <pviktori@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
|
||||
class SetseboolError(StandardError):
|
||||
"""Raised when setting a SELinux boolean fails
|
||||
|
||||
:param failed: Dictionary mapping boolean names to intended values
|
||||
to their intended values, for booleans that cound not be set
|
||||
:param command: Command the user can run to set the booleans
|
||||
|
||||
The initializer arguments are copied to attributes of the same name.
|
||||
"""
|
||||
def __init__(self, failed, command):
|
||||
message = "Could not set SELinux booleans: %s" % ' '.join(
|
||||
'%s=%s' % (name, value) for name, value in failed.items())
|
||||
super(SetseboolError, self).__init__(message)
|
||||
self.failed = failed
|
||||
self.command = command
|
||||
|
||||
def format_service_warning(self, service_name):
|
||||
"""Format warning for display when this is raised from service install
|
||||
"""
|
||||
return '\n'.join([
|
||||
'WARNING: %(err)s',
|
||||
'',
|
||||
'The %(service)s may not function correctly until ',
|
||||
'the booleans are successfully changed with the command:',
|
||||
' %(cmd)s',
|
||||
'Try updating the policycoreutils and selinux-policy packages.'
|
||||
]) % {'err': self, 'service': service_name, 'cmd': self.command}
|
@ -36,23 +36,17 @@ from ipalib.util import normalize_zone
|
||||
from ipapython.dn import DN
|
||||
from ipapython import sysrestore
|
||||
from ipapython import ipautil
|
||||
from ipapython.ipa_log_manager import *
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
import ipapython.errors
|
||||
|
||||
import ipaclient.ipachangeconf
|
||||
from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
from ipaplatform.tasks import tasks
|
||||
|
||||
|
||||
ALLOWED_NETBIOS_CHARS = string.ascii_uppercase + string.digits
|
||||
|
||||
SELINUX_WARNING = """
|
||||
WARNING: could not set selinux boolean(s) %(var)s to true. The adtrust
|
||||
service may not function correctly until this boolean is successfully
|
||||
change with the command:
|
||||
/usr/sbin/setsebool -P %(var)s true
|
||||
Try updating the policycoreutils and selinux-policy packages.
|
||||
"""
|
||||
|
||||
UPGRADE_ERROR = """
|
||||
Entry %(dn)s does not exist.
|
||||
This means upgrade from IPA 2.x to 3.x did not went well and required S4U2Proxy
|
||||
@ -60,6 +54,9 @@ configuration was not set up properly. Please run ipa-ldap-updater manually
|
||||
and re-run ipa-adtrust-instal again afterwards.
|
||||
"""
|
||||
|
||||
SELINUX_BOOLEAN_SETTINGS = {'samba_portmapper': 'on'}
|
||||
|
||||
|
||||
def check_inst():
|
||||
for smbfile in [paths.SMBD, paths.NET]:
|
||||
if not os.path.exists(smbfile):
|
||||
@ -148,7 +145,6 @@ class ADTRUSTInstance(service.Service):
|
||||
# Constants
|
||||
self.smb_conf = paths.SMB_CONF
|
||||
self.samba_keytab = paths.SAMBA_KEYTAB
|
||||
self.selinux_booleans = ["samba_portmapper"]
|
||||
self.cifs_hosts = []
|
||||
|
||||
# Values obtained from API.env
|
||||
@ -611,35 +607,11 @@ class ADTRUSTInstance(service.Service):
|
||||
add_rr(zone, win_srv, "SRV", rec)
|
||||
|
||||
def __configure_selinux_for_smbd(self):
|
||||
selinux = False
|
||||
try:
|
||||
if (os.path.exists(paths.SELINUXENABLED)):
|
||||
ipautil.run([paths.SELINUXENABLED])
|
||||
selinux = True
|
||||
except ipautil.CalledProcessError:
|
||||
# selinuxenabled returns 1 if not enabled
|
||||
pass
|
||||
|
||||
if selinux:
|
||||
# Don't assume all booleans are available
|
||||
sebools = []
|
||||
for var in self.selinux_booleans:
|
||||
try:
|
||||
(stdout, stderr, returncode) = ipautil.run([paths.GETSEBOOL, var])
|
||||
if stdout and not stderr and returncode == 0:
|
||||
self.backup_state(var, stdout.split()[2])
|
||||
sebools.append(var)
|
||||
except:
|
||||
pass
|
||||
|
||||
if sebools:
|
||||
bools = [var + "=true" for var in sebools]
|
||||
args = [paths.SETSEBOOL, "-P"]
|
||||
args.extend(bools);
|
||||
try:
|
||||
ipautil.run(args)
|
||||
except:
|
||||
self.print_msg(SELINUX_WARNING % dict(var=','.join(sebools)))
|
||||
tasks.set_selinux_booleans(SELINUX_BOOLEAN_SETTINGS,
|
||||
self.backup_state)
|
||||
except ipapython.errors.SetseboolError as e:
|
||||
self.print_msg(e.format_service_warning('adtrust service'))
|
||||
|
||||
def __mod_krb5_conf(self):
|
||||
"""
|
||||
@ -909,14 +881,12 @@ class ADTRUSTInstance(service.Service):
|
||||
# we should not restore smb.conf
|
||||
|
||||
# Restore the state of affected selinux booleans
|
||||
for var in self.selinux_booleans:
|
||||
sebool_state = self.restore_state(var)
|
||||
if not sebool_state is None:
|
||||
try:
|
||||
ipautil.run([paths.SETSEBOOL,
|
||||
"-P", var, sebool_state])
|
||||
except Exception:
|
||||
self.print_msg(SELINUX_WARNING % dict(var=var))
|
||||
boolean_states = {name: self.restore_state(name)
|
||||
for name in SELINUX_BOOLEAN_SETTINGS}
|
||||
try:
|
||||
tasks.set_selinux_booleans(boolean_states)
|
||||
except ipapython.errors.SetseboolError as e:
|
||||
self.print_msg('WARNING: ' + str(e))
|
||||
|
||||
# Remove samba's credentials cache
|
||||
krb5cc_samba = paths.KRB5CC_SAMBA
|
||||
|
@ -22,7 +22,6 @@ import os.path
|
||||
import tempfile
|
||||
import pwd
|
||||
import shutil
|
||||
import stat
|
||||
import re
|
||||
|
||||
import service
|
||||
@ -31,12 +30,18 @@ import installutils
|
||||
from ipapython import sysrestore
|
||||
from ipapython import ipautil
|
||||
from ipapython import dogtag
|
||||
from ipapython.ipa_log_manager import *
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
import ipapython.errors
|
||||
from ipaserver.install import sysupgrade
|
||||
from ipalib import api
|
||||
from ipaplatform.tasks import tasks
|
||||
from ipaplatform.paths import paths
|
||||
from ipalib.constants import CACERT
|
||||
|
||||
|
||||
SELINUX_BOOLEAN_SETTINGS = dict(
|
||||
httpd_can_network_connect='on',
|
||||
httpd_manage_ipa='on',
|
||||
)
|
||||
|
||||
|
||||
def httpd_443_configured():
|
||||
@ -135,67 +140,11 @@ class HTTPInstance(service.Service):
|
||||
self.ldap_enable('HTTP', self.fqdn, self.dm_password, self.suffix)
|
||||
|
||||
def configure_selinux_for_httpd(self):
|
||||
def get_setsebool_args(changes):
|
||||
if len(changes) == 1:
|
||||
# workaround https://bugzilla.redhat.com/show_bug.cgi?id=825163
|
||||
updates = changes.items()[0]
|
||||
else:
|
||||
updates = ["%s=%s" % update for update in changes.iteritems()]
|
||||
|
||||
args = [paths.SETSEBOOL, "-P"]
|
||||
args.extend(updates)
|
||||
|
||||
return args
|
||||
|
||||
selinux = False
|
||||
try:
|
||||
if (os.path.exists(paths.SELINUXENABLED)):
|
||||
ipautil.run([paths.SELINUXENABLED])
|
||||
selinux = True
|
||||
except ipautil.CalledProcessError:
|
||||
# selinuxenabled returns 1 if not enabled
|
||||
pass
|
||||
|
||||
if selinux:
|
||||
# Don't assume all vars are available
|
||||
updated_vars = {}
|
||||
failed_vars = {}
|
||||
required_settings = (("httpd_can_network_connect", "on"),
|
||||
("httpd_manage_ipa", "on"))
|
||||
for setting, state in required_settings:
|
||||
try:
|
||||
(stdout, stderr, returncode) = ipautil.run([paths.GETSEBOOL, setting])
|
||||
original_state = stdout.split()[2]
|
||||
self.backup_state(setting, original_state)
|
||||
|
||||
if original_state != state:
|
||||
updated_vars[setting] = state
|
||||
except ipautil.CalledProcessError, e:
|
||||
root_logger.debug("Cannot get SELinux boolean '%s': %s", setting, e)
|
||||
failed_vars[setting] = state
|
||||
|
||||
# Allow apache to connect to the dogtag UI and the session cache
|
||||
# This can still fail even if selinux is enabled. Execute these
|
||||
# together so it is speedier.
|
||||
if updated_vars:
|
||||
args = get_setsebool_args(updated_vars)
|
||||
try:
|
||||
ipautil.run(args)
|
||||
except ipautil.CalledProcessError:
|
||||
failed_vars.update(updated_vars)
|
||||
|
||||
if failed_vars:
|
||||
args = get_setsebool_args(failed_vars)
|
||||
names = [update[0] for update in updated_vars]
|
||||
message = ['WARNING: could not set the following SELinux boolean(s):']
|
||||
for update in failed_vars.iteritems():
|
||||
message.append(' %s -> %s' % update)
|
||||
message.append('The web interface may not function correctly until the booleans')
|
||||
message.append('are successfully changed with the command:')
|
||||
message.append(' '.join(args))
|
||||
message.append('Try updating the policycoreutils and selinux-policy packages.')
|
||||
|
||||
self.print_msg("\n".join(message))
|
||||
tasks.set_selinux_booleans(SELINUX_BOOLEAN_SETTINGS,
|
||||
self.backup_state)
|
||||
except ipapython.errors.SetseboolError as e:
|
||||
self.print_msg(e.format_service_warning('web interface'))
|
||||
|
||||
def __create_http_keytab(self):
|
||||
installutils.kadmin_addprinc(self.principal)
|
||||
@ -412,14 +361,13 @@ class HTTPInstance(service.Service):
|
||||
installutils.remove_file(paths.HTTPD_IPA_CONF)
|
||||
installutils.remove_file(paths.HTTPD_IPA_PKI_PROXY_CONF)
|
||||
|
||||
for var in ["httpd_can_network_connect", "httpd_manage_ipa"]:
|
||||
sebool_state = self.restore_state(var)
|
||||
if not sebool_state is None:
|
||||
try:
|
||||
ipautil.run([paths.SETSEBOOL, "-P", var, sebool_state])
|
||||
except ipautil.CalledProcessError, e:
|
||||
self.print_msg("Cannot restore SELinux boolean '%s' back to '%s': %s" \
|
||||
% (var, sebool_state, e))
|
||||
# Restore SELinux boolean states
|
||||
boolean_states = {name: self.restore_state(name)
|
||||
for name in SELINUX_BOOLEAN_SETTINGS}
|
||||
try:
|
||||
tasks.set_selinux_booleans(boolean_states)
|
||||
except ipapython.errors.SetseboolError as e:
|
||||
self.print_msg('WARNING: ' + str(e))
|
||||
|
||||
if not running is None and running:
|
||||
self.start()
|
||||
|
Loading…
Reference in New Issue
Block a user