Skip to content

Commit

Permalink
Use tasks to configure automount nsswitch settings
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
rcritten committed Aug 29, 2019
1 parent e5af8c1 commit 41ef8fb
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 145 deletions.
72 changes: 2 additions & 70 deletions ipaclient/install/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

from . import automount, timeconf, sssd
from ipaclient import discovery
from .ipachangeconf import IPAChangeConf
from ipapython.ipachangeconf import IPAChangeConf

NoneType = type(None)

Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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')

Expand Down
80 changes: 5 additions & 75 deletions ipaclient/install/ipa_client_automount.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@

# 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,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
153 changes: 153 additions & 0 deletions ipaplatform/base/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from ipaplatform.constants import constants
from ipaplatform.paths import paths
from ipapython import ipautil
from ipapython.ipachangeconf import IPAChangeConf

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -337,5 +338,157 @@ def restore_pkcs11_modules(self, fstore):
"""
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()
1 change: 1 addition & 0 deletions ipaplatform/redhat/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
19 changes: 19 additions & 0 deletions ipaplatform/redhat/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,4 +744,23 @@ def restore_pkcs11_modules(self, fstore):

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()

0 comments on commit 41ef8fb

Please sign in to comment.