mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-01-11 00:31:56 -06:00
c78d1341ad
Subordinate ids are now handled by a new plugin class and stored in separate entries in the cn=subids,cn=accounts subtree. Signed-off-by: Christian Heimes <cheimes@redhat.com> Reviewed-By: Francois Cami <fcami@redhat.com> Reviewed-By: Rob Crittenden <rcritten@redhat.com>
148 lines
4.8 KiB
Python
148 lines
4.8 KiB
Python
#
|
|
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
|
#
|
|
|
|
import logging
|
|
import time
|
|
import ldap
|
|
|
|
from ipalib.plugable import Registry
|
|
from ipalib import errors
|
|
from ipalib import Updater
|
|
from ipapython.dn import DN
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
register = Registry()
|
|
|
|
@register()
|
|
class update_dna_shared_config(Updater):
|
|
dna_plugin_names = ('posix IDs', 'Subordinate IDs')
|
|
|
|
dna_plugin_dn = DN(
|
|
('cn', 'Distributed Numeric Assignment Plugin'),
|
|
('cn', 'plugins'),
|
|
('cn', 'config')
|
|
)
|
|
|
|
def is_dna_enabled(self):
|
|
"""Check the plugin is enabled
|
|
|
|
Else it is useless to update the shared entry
|
|
"""
|
|
try:
|
|
entry = self.api.Backend.ldap2.get_entry(self.dna_plugin_dn)
|
|
enabled = entry.single_value.get('nsslapd-pluginenabled')
|
|
if enabled.lower() == 'off':
|
|
return False
|
|
else:
|
|
return True
|
|
except errors.NotFound:
|
|
logger.error("Could not find DNA plugin entry: %s",
|
|
self.dna_plugin_dn)
|
|
return False
|
|
|
|
def get_shared_cfg(self, plugin_name):
|
|
dna_config_base = DN(('cn', plugin_name), self.dna_plugin_dn)
|
|
try:
|
|
entry = self.api.Backend.ldap2.get_entry(dna_config_base)
|
|
except errors.NotFound:
|
|
logger.error("Could not find DNA config entry: %s",
|
|
dna_config_base)
|
|
return False, ()
|
|
else:
|
|
logger.debug('Found DNA config %s', dna_config_base)
|
|
|
|
sharedcfgdn = entry.single_value.get("dnaSharedCfgDN")
|
|
if sharedcfgdn is not None:
|
|
sharedcfgdn = DN(sharedcfgdn)
|
|
logger.debug("dnaSharedCfgDN: %s", sharedcfgdn)
|
|
return sharedcfgdn
|
|
else:
|
|
logger.error(
|
|
"Could not find DNA shared config DN in entry: %s",
|
|
dna_config_base)
|
|
return None
|
|
|
|
def update_shared_cfg(self, sharedcfgdn, **options):
|
|
"""Update the shared config entry related to that host
|
|
|
|
If the shared config entry already exists (like upgrade)
|
|
the update occurs immediately without sleep.
|
|
|
|
If the shared config entry does not exist (fresh install)
|
|
DS server waits for 30s after its startup to create it.
|
|
Startup likely occurred few sec before this function is
|
|
called so this loop will wait for 30s max.
|
|
|
|
In case the server is not able to create the entry
|
|
The loop gives a grace period of slightly more than 60 seconds
|
|
before it logs a failure and aborts the update.
|
|
"""
|
|
method = options.get('method', "SASL/GSSAPI")
|
|
protocol = options.get('protocol', "LDAP")
|
|
|
|
max_wait = 30 # times 2 second sleep
|
|
|
|
conn = self.api.Backend.ldap2
|
|
fqdn = self.api.env.host
|
|
|
|
for _i in range(0, max_wait + 1):
|
|
try:
|
|
entries = conn.get_entries(
|
|
sharedcfgdn, scope=ldap.SCOPE_ONELEVEL,
|
|
filter='dnaHostname=%s' % fqdn
|
|
)
|
|
# There must be two entries:
|
|
# - dnaHostname=fqdn+dnaPortNum=0
|
|
# - dnaHostname=fqdn+dnaPortNum=389
|
|
if len(entries) >= 2:
|
|
break
|
|
|
|
logger.debug("Got only one entry. Retry again in 2 sec.")
|
|
time.sleep(2)
|
|
except errors.NotFound:
|
|
logger.debug(
|
|
"Unable to find DNA shared config entry for "
|
|
"dnaHostname=%s (under %s) so far. Retry in 2 sec.",
|
|
fqdn, sharedcfgdn
|
|
)
|
|
time.sleep(2)
|
|
else:
|
|
logger.error(
|
|
"Could not get dnaHostname entries in %s seconds",
|
|
max_wait * 2
|
|
)
|
|
return False
|
|
|
|
# time to set the bind method and the protocol in the
|
|
# shared config entries
|
|
for entry in entries:
|
|
entry["dnaRemoteBindMethod"] = method
|
|
entry["dnaRemoteConnProtocol"] = protocol
|
|
try:
|
|
conn.update_entry(entry)
|
|
except errors.EmptyModlist:
|
|
logger.debug("Entry %s is already updated", entry.dn)
|
|
except Exception as e:
|
|
logger.error(
|
|
"Failed to set SASL/GSSAPI bind method/protocol "
|
|
"in entry %s: %s", entry, e
|
|
)
|
|
else:
|
|
logger.debug("Updated entry %s", entry.dn)
|
|
|
|
return True
|
|
|
|
def execute(self, **options):
|
|
if not self.is_dna_enabled():
|
|
return False, ()
|
|
|
|
for plugin_name in self.dna_plugin_names:
|
|
sharedcfgdn = self.get_shared_cfg(plugin_name)
|
|
if sharedcfgdn is not None:
|
|
self.update_shared_cfg(sharedcfgdn, **options)
|
|
|
|
# no restart, no update
|
|
return False, ()
|