Use tasks to configure automount nsswitch settings

authselect doesn't allow one to directly write to
/etc/nsswitch.conf. It will complain bitterly if it
detects it and will refuse to work until reset.

Instead it wants the user to write to
/etc/authselect/user-nsswitch.conf and then it will handle
merging in any differences.

To complicate matters some databases are not user configurable
like passwd, group and of course, automount. There are some
undocumented options to allow one to override these though so
we utilize that.

tasks are used so that authselect-based installations can still
write directly to /etc/nsswitch.conf and operate as it used to.

Reviewed-By: Francois Cami <fcami@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Rob Critenden 2019-08-16 18:10:15 +00:00 committed by Rob Crittenden
parent e5af8c19a9
commit 41ef8fba31
5 changed files with 180 additions and 145 deletions

View File

@ -66,7 +66,7 @@ from ipapython import version
from . import automount, timeconf, sssd
from ipaclient import discovery
from .ipachangeconf import IPAChangeConf
from ipapython.ipachangeconf import IPAChangeConf
NoneType = type(None)
@ -281,72 +281,6 @@ def is_ipa_client_installed(fstore, on_master=False):
return installed
def configure_nsswitch_database(fstore, database, services, preserve=True,
append=True, default_value=()):
"""
Edits the specified nsswitch.conf database (e.g. passwd, group, sudoers)
to use the specified service(s).
Arguments:
fstore - FileStore to backup the nsswitch.conf
database - database configuration that should be ammended,
e.g. 'sudoers'
service - list of services that should be added, e.g. ['sss']
preserve - if True, the already configured services will be preserved
The next arguments modify the behaviour if preserve=True:
append - if True, the services will be appended, if False, prepended
default_value - list of services that are considered as default (if
the database is not mentioned in nsswitch.conf), e.g.
['files']
"""
# Backup the original version of nsswitch.conf, we're going to edit it now
if not fstore.has_file(paths.NSSWITCH_CONF):
fstore.backup_file(paths.NSSWITCH_CONF)
conf = IPAChangeConf("IPA Installer")
conf.setOptionAssignment(':')
if preserve:
# Read the existing configuration
with open(paths.NSSWITCH_CONF, 'r') as f:
opts = conf.parse(f)
raw_database_entry = conf.findOpts(opts, 'option', database)[1]
# Detect the list of already configured services
if not raw_database_entry:
# If there is no database entry, database is not present in
# the nsswitch.conf. Set the list of services to the
# default list, if passed.
configured_services = list(default_value)
else:
configured_services = raw_database_entry['value'].strip().split()
# Make sure no service is added if already mentioned in the list
added_services = [s for s in services
if s not in configured_services]
# Prepend / append the list of new services
if append:
new_value = ' ' + ' '.join(configured_services + added_services)
else:
new_value = ' ' + ' '.join(added_services + configured_services)
else:
# Preserve not set, let's rewrite existing configuration
new_value = ' ' + ' '.join(services)
# Set new services as sources for database
opts = [
conf.setOption(database, new_value),
conf.emptyLine(),
]
conf.changeConf(paths.NSSWITCH_CONF, opts)
logger.info("Configured %s in %s", database, paths.NSSWITCH_CONF)
def configure_ipa_conf(
fstore, cli_basedn, cli_realm, cli_domain, cli_server, hostname):
ipaconf = IPAChangeConf("IPA Installer")
@ -948,9 +882,7 @@ def configure_sssd_conf(
"Unable to activate the SUDO service in SSSD config.")
sssdconfig.activate_service('sudo')
configure_nsswitch_database(
fstore, 'sudoers', ['sss'],
default_value=['files'])
tasks.enable_sssd_sudo(fstore)
domain.add_provider('ipa', 'id')

View File

@ -41,7 +41,8 @@ from six.moves.urllib.parse import urlsplit
# pylint: enable=import-error
from optparse import OptionParser # pylint: disable=deprecated-module
from ipaclient.install import ipachangeconf, ipadiscovery
from ipapython import ipachangeconf
from ipaclient.install import ipadiscovery
from ipaclient.install.client import (
CLIENT_NOT_CONFIGURED,
CLIENT_ALREADY_CONFIGURED,
@ -177,44 +178,6 @@ def configure_xml(fstore):
print("Configured %s" % authconf)
def configure_nsswitch(statestore, options):
"""
Point automount to ldap in nsswitch.conf.
This function is for non-SSSD setups only.
"""
conf = ipachangeconf.IPAChangeConf("IPA Installer")
conf.setOptionAssignment(':')
with open(paths.NSSWITCH_CONF, 'r') as f:
current_opts = conf.parse(f)
current_nss_value = conf.findOpts(
current_opts, name='automount', type='option'
)[1]
if current_nss_value is None:
# no automount database present
current_nss_value = False # None cannot be backed up
else:
current_nss_value = current_nss_value['value']
statestore.backup_state(
'ipa-client-automount-nsswitch', 'previous-automount',
current_nss_value
)
nss_value = ' files ldap'
opts = [
{
'name': 'automount',
'type': 'option',
'action': 'set',
'value': nss_value,
},
{'name': 'empty', 'type': 'empty'},
]
conf.changeConf(paths.NSSWITCH_CONF, opts)
print("Configured %s" % paths.NSSWITCH_CONF)
def configure_autofs_sssd(fstore, statestore, autodiscover, options):
try:
sssdconfig = SSSDConfig.SSSDConfig()
@ -339,41 +302,8 @@ def uninstall(fstore, statestore):
]
STATES = ['autofs', 'rpcidmapd', 'rpcgssd']
if statestore.get_state(
'ipa-client-automount-nsswitch', 'previous-automount'
) is False:
# Previous nsswitch.conf had no automount database configured
# so remove it.
conf = ipachangeconf.IPAChangeConf("IPA automount installer")
conf.setOptionAssignment(':')
changes = [conf.rmOption('automount')]
conf.changeConf(paths.NSSWITCH_CONF, changes)
tasks.restore_context(paths.NSSWITCH_CONF)
statestore.delete_state(
'ipa-client-automount-nsswitch', 'previous-automount'
)
elif statestore.get_state(
'ipa-client-automount-nsswitch', 'previous-automount'
) is not None:
nss_value = statestore.get_state(
'ipa-client-automount-nsswitch', 'previous-automount'
)
opts = [
{
'name': 'automount',
'type': 'option',
'action': 'set',
'value': nss_value,
},
{'name': 'empty', 'type': 'empty'},
]
conf = ipachangeconf.IPAChangeConf("IPA automount installer")
conf.setOptionAssignment(':')
conf.changeConf(paths.NSSWITCH_CONF, opts)
tasks.restore_context(paths.NSSWITCH_CONF)
statestore.delete_state(
'ipa-client-automount-nsswitch', 'previous-automount'
)
if not statestore.get_state('autofs', 'sssd'):
tasks.disable_ldap_automount(statestore)
if not any(fstore.has_file(f) for f in RESTORE_FILES) or not any(
statestore.has_state(s) for s in STATES
@ -627,7 +557,7 @@ def configure_automount():
try:
if not options.sssd:
configure_nsswitch(statestore, options)
tasks.enable_ldap_automount(statestore)
configure_nfs(fstore, statestore, options)
if options.sssd:
configure_autofs_sssd(fstore, statestore, autodiscover, options)

View File

@ -32,6 +32,7 @@ from pkg_resources import parse_version
from ipaplatform.constants import constants
from ipaplatform.paths import paths
from ipapython import ipautil
from ipapython.ipachangeconf import IPAChangeConf
logger = logging.getLogger(__name__)
@ -337,5 +338,157 @@ class BaseTaskNamespace:
"""
raise NotImplementedError
def configure_nsswitch_database(self, fstore, database, services,
preserve=True, append=True,
default_value=()):
"""
Edits the specified nsswitch.conf database (e.g. passwd, group,
sudoers) to use the specified service(s).
Arguments:
fstore - FileStore to backup the nsswitch.conf
database - database configuration that should be ammended,
e.g. 'sudoers'
service - list of services that should be added, e.g. ['sss']
preserve - if True, the already configured services will be
preserved
The next arguments modify the behaviour if preserve=True:
append - if True, the services will be appended, if False,
prepended
default_value - list of services that are considered as default (if
the database is not mentioned in nsswitch.conf),
e.g. ['files']
"""
# Backup the original version of nsswitch.conf, we're going to edit it
# now
if not fstore.has_file(paths.NSSWITCH_CONF):
fstore.backup_file(paths.NSSWITCH_CONF)
conf = IPAChangeConf("IPA Installer")
conf.setOptionAssignment(':')
if preserve:
# Read the existing configuration
with open(paths.NSSWITCH_CONF, 'r') as f:
opts = conf.parse(f)
raw_database_entry = conf.findOpts(opts, 'option', database)[1]
# Detect the list of already configured services
if not raw_database_entry:
# If there is no database entry, database is not present in
# the nsswitch.conf. Set the list of services to the
# default list, if passed.
configured_services = list(default_value)
else:
configured_services = raw_database_entry[
'value'].strip().split()
# Make sure no service is added if already mentioned in the list
added_services = [s for s in services
if s not in configured_services]
# Prepend / append the list of new services
if append:
new_value = ' ' + ' '.join(configured_services +
added_services)
else:
new_value = ' ' + ' '.join(added_services +
configured_services)
else:
# Preserve not set, let's rewrite existing configuration
new_value = ' ' + ' '.join(services)
# Set new services as sources for database
opts = [
conf.setOption(database, new_value),
conf.emptyLine(),
]
conf.changeConf(paths.NSSWITCH_CONF, opts)
logger.info("Configured %s in %s", database, paths.NSSWITCH_CONF)
def enable_sssd_sudo(self, fstore):
"""Configure nsswitch.conf to use sssd for sudo"""
self.configure_nsswitch_database(
fstore, 'sudoers', ['sss'],
default_value=['files'])
def enable_ldap_automount(self, statestore):
"""
Point automount to ldap in nsswitch.conf.
This function is for non-SSSD setups only.
"""
conf = IPAChangeConf("IPA Installer")
conf.setOptionAssignment(':')
with open(paths.NSSWITCH_CONF, 'r') as f:
current_opts = conf.parse(f)
current_nss_value = conf.findOpts(
current_opts, name='automount', type='option'
)[1]
if current_nss_value is None:
# no automount database present
current_nss_value = False # None cannot be backed up
else:
current_nss_value = current_nss_value['value']
statestore.backup_state(
'ipa-client-automount-nsswitch', 'previous-automount',
current_nss_value
)
nss_value = ' files ldap'
opts = [
{
'name': 'automount',
'type': 'option',
'action': 'set',
'value': nss_value,
},
{'name': 'empty', 'type': 'empty'},
]
conf.changeConf(paths.NSSWITCH_CONF, opts)
logger.info("Configured %s", paths.NSSWITCH_CONF)
def disable_ldap_automount(self, statestore):
"""Disable automount using LDAP"""
if statestore.get_state(
'ipa-client-automount-nsswitch', 'previous-automount'
) is False:
# Previous nsswitch.conf had no automount database configured
# so remove it.
conf = IPAChangeConf("IPA automount installer")
conf.setOptionAssignment(':')
changes = [conf.rmOption('automount')]
conf.changeConf(paths.NSSWITCH_CONF, changes)
self.restore_context(paths.NSSWITCH_CONF)
statestore.delete_state(
'ipa-client-automount-nsswitch', 'previous-automount'
)
elif statestore.get_state(
'ipa-client-automount-nsswitch', 'previous-automount'
) is not None:
nss_value = statestore.get_state(
'ipa-client-automount-nsswitch', 'previous-automount'
)
opts = [
{
'name': 'automount',
'type': 'option',
'action': 'set',
'value': nss_value,
},
{'name': 'empty', 'type': 'empty'},
]
conf = IPAChangeConf("IPA automount installer")
conf.setOptionAssignment(':')
conf.changeConf(paths.NSSWITCH_CONF, opts)
self.restore_context(paths.NSSWITCH_CONF)
statestore.delete_state(
'ipa-client-automount-nsswitch', 'previous-automount'
)
tasks = BaseTaskNamespace()

View File

@ -39,6 +39,7 @@ class RedHatPathNamespace(BasePathNamespace):
AUTHCONFIG = '/usr/sbin/authconfig'
AUTHSELECT = '/usr/bin/authselect'
SYSCONF_NETWORK = '/etc/sysconfig/network'
NSSWITCH_CONF = '/etc/authselect/user-nsswitch.conf'
paths = RedHatPathNamespace()

View File

@ -744,4 +744,23 @@ class RedHatTaskNamespace(BaseTaskNamespace):
return filenames
def enable_ldap_automount(self, statestore):
"""
Point automount to ldap in nsswitch.conf.
This function is for non-SSSD setups only.
"""
super(RedHatTaskNamespace, self).enable_ldap_automount(statestore)
authselect_cmd = [paths.AUTHSELECT, "enable-feature",
"with-custom-automount"]
ipautil.run(authselect_cmd)
def disable_ldap_automount(self, statestore):
"""Disable ldap-based automount"""
super(RedHatTaskNamespace, self).disable_ldap_automount(statestore)
authselect_cmd = [paths.AUTHSELECT, "disable-feature",
"with-custom-automount"]
ipautil.run(authselect_cmd)
tasks = RedHatTaskNamespace()