Import Upstream version 4.12.4
This commit is contained in:
79
ipaserver/install/plugins/add_admin_krbcanonicalname.py
Normal file
79
ipaserver/install/plugins/add_admin_krbcanonicalname.py
Normal file
@@ -0,0 +1,79 @@
|
||||
#
|
||||
# Copyright (C) 2025 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
|
||||
from ipalib import errors
|
||||
from ipalib import Registry
|
||||
from ipalib import Updater
|
||||
from ipapython.dn import DN
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
register = Registry()
|
||||
|
||||
|
||||
@register()
|
||||
class add_admin_krbcanonicalname(Updater):
|
||||
"""
|
||||
Ensures that only the admin user has the krbCanonicalName of
|
||||
admin@$REALM.
|
||||
"""
|
||||
|
||||
def execute(self, **options):
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
search_filter = (
|
||||
"(krbcanonicalname=admin@{})".format(self.api.env.realm))
|
||||
try:
|
||||
(entries, _truncated) = ldap.find_entries(
|
||||
filter=search_filter, base_dn=self.api.env.basedn,
|
||||
time_limit=0, size_limit=0)
|
||||
except errors.EmptyResult:
|
||||
logger.debug("add_admin_krbcanonicalname: No user set with "
|
||||
"admin krbcanonicalname")
|
||||
entries = []
|
||||
# fall through
|
||||
except errors.ExecutionError as e:
|
||||
logger.error("add_admin_krbcanonicalname: Can not get list "
|
||||
"of krbcanonicalname: %s", e)
|
||||
return False, []
|
||||
|
||||
admin_set = False
|
||||
# admin should be only user with admin@ as krbcanonicalname
|
||||
# It has a uniquness setting so there can be only one, we
|
||||
# just didn't automatically set it for admin.
|
||||
for entry in entries:
|
||||
if entry.single_value.get('uid') != 'admin':
|
||||
logger.critical(
|
||||
"add_admin_krbcanonicalname: "
|
||||
"entry %s has a krbcanonicalname of admin. Removing.",
|
||||
entry.dn)
|
||||
del entry['krbcanonicalname']
|
||||
ldap.update_entry(entry)
|
||||
else:
|
||||
admin_set = True
|
||||
|
||||
if not admin_set:
|
||||
dn = DN(
|
||||
('uid', 'admin'),
|
||||
self.api.env.container_user,
|
||||
self.api.env.basedn)
|
||||
entry = ldap.get_entry(dn)
|
||||
entry['krbcanonicalname'] = 'admin@%s' % self.api.env.realm
|
||||
try:
|
||||
ldap.update_entry(entry)
|
||||
except errors.DuplicateEntry:
|
||||
logger.critical(
|
||||
"add_admin_krbcanonicalname: "
|
||||
"Failed to set krbcanonicalname on admin. It is set "
|
||||
"on another entry.")
|
||||
except errors.ExecutionError as e:
|
||||
logger.critical(
|
||||
"add_admin_krbcanonicalname: "
|
||||
"Failed to set krbcanonicalname on admin: %s", e)
|
||||
|
||||
return False, []
|
||||
@@ -702,7 +702,7 @@ class update_tdo_to_new_layout(Updater):
|
||||
nbt=nbt_name, realm=self.api.env.realm)
|
||||
tgt_principal = self.tgt_principal_template.format(
|
||||
remote=nbt_name, local=self.api.env.realm)
|
||||
self.set_krb_principal([nbt_principal, tgt_principal],
|
||||
self.set_krb_principal([tgt_principal, nbt_principal],
|
||||
passwd_incoming,
|
||||
t_dn,
|
||||
flags=self.KRB_PRINC_CREATE_DEFAULT)
|
||||
@@ -754,7 +754,8 @@ class update_host_cifs_keytabs(Updater):
|
||||
"""
|
||||
|
||||
host_princ_template = "host/{master}@{realm}"
|
||||
valid_etypes = ['aes256-cts-hmac-sha1-96', 'aes128-cts-hmac-sha1-96']
|
||||
valid_etypes = ['aes256-cts-hmac-sha384-192', 'aes128-cts-hmac-sha256-128',
|
||||
'aes256-cts-hmac-sha1-96', 'aes128-cts-hmac-sha1-96']
|
||||
|
||||
def extract_key_refs(self, keytab):
|
||||
host_princ = self.host_princ_template.format(
|
||||
|
||||
@@ -28,7 +28,6 @@ from ipalib.install import certmonger
|
||||
from ipalib.plugable import Registry
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.dn import DN
|
||||
from ipapython import directivesetter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -90,7 +89,7 @@ class update_ca_renewal_master(Updater):
|
||||
if ca_name is None:
|
||||
logger.warning(
|
||||
"certmonger request for RA cert is missing ca_name, "
|
||||
"assuming local CA is renewal slave")
|
||||
"assuming local CA is not a renewal master.")
|
||||
return False, []
|
||||
ca_name = ca_name.strip()
|
||||
|
||||
@@ -103,23 +102,14 @@ class update_ca_renewal_master(Updater):
|
||||
else:
|
||||
logger.warning(
|
||||
"certmonger request for RA cert has unknown ca_name '%s', "
|
||||
"assuming local CA is renewal slave", ca_name)
|
||||
"assuming local CA is not a renewal master", ca_name)
|
||||
return False, []
|
||||
else:
|
||||
logger.debug("certmonger request for RA cert not found")
|
||||
|
||||
config = directivesetter.get_directive(
|
||||
paths.CA_CS_CFG_PATH, 'subsystem.select', '=')
|
||||
|
||||
if config == 'New':
|
||||
pass
|
||||
elif config == 'Clone':
|
||||
if not ca.is_crlgen_enabled():
|
||||
# CA is not a renewal master
|
||||
return False, []
|
||||
else:
|
||||
logger.warning(
|
||||
"CS.cfg has unknown subsystem.select value '%s', "
|
||||
"assuming local CA is renewal slave", config)
|
||||
return (False, False, [])
|
||||
|
||||
update = {
|
||||
'dn': dn,
|
||||
|
||||
@@ -161,11 +161,11 @@ class update_ipaconfigstring_dnsversion_to_ipadnsversion(Updater):
|
||||
@register()
|
||||
class update_dnszones(Updater):
|
||||
"""
|
||||
Update all zones to meet requirements in the new FreeIPA versions
|
||||
Update all zones to meet requirements in the new IPA versions
|
||||
|
||||
1) AllowQuery and AllowTransfer
|
||||
Set AllowQuery and AllowTransfer ACLs in all zones that may be configured
|
||||
in an upgraded FreeIPA instance.
|
||||
in an upgraded IPA instance.
|
||||
|
||||
Upgrading to new version of bind-dyndb-ldap and having these ACLs empty
|
||||
would result in a leak of potentially sensitive DNS information as
|
||||
@@ -173,7 +173,7 @@ class update_dnszones(Updater):
|
||||
or LDAP.
|
||||
|
||||
This plugin disables the zone transfer by default so that it needs to be
|
||||
explicitly enabled by FreeIPA Administrator.
|
||||
explicitly enabled by IPA Administrator.
|
||||
|
||||
2) Update policy
|
||||
SSH public key support includes a feature to automatically add/update
|
||||
@@ -272,7 +272,7 @@ class update_dns_limits(Updater):
|
||||
@register()
|
||||
class update_master_to_dnsforwardzones(DNSUpdater):
|
||||
"""
|
||||
Update all zones to meet requirements in the new FreeIPA versions
|
||||
Update all zones to meet requirements in the new IPA versions
|
||||
|
||||
All masters zones with specified forwarders, and forward-policy different
|
||||
than none, will be tranformed to forward zones.
|
||||
@@ -420,7 +420,7 @@ class update_dnsforward_emptyzones(DNSUpdater):
|
||||
|
||||
BIND ignores conflicting forwarding configuration
|
||||
when forwarding policy != only.
|
||||
bind-dyndb-ldap 9.0+ will do the same so we have to adjust FreeIPA zones
|
||||
bind-dyndb-ldap 9.0+ will do the same so we have to adjust IPA zones
|
||||
accordingly.
|
||||
"""
|
||||
backup_filename = u'dns-forwarding-empty-zones-%Y-%m-%d-%H-%M-%S.ldif'
|
||||
@@ -551,3 +551,111 @@ class update_dnsserver_configuration_into_ldap(DNSUpdater):
|
||||
"created in LDAP database")
|
||||
sysupgrade.set_upgrade_state('dns', 'server_config_to_ldap', True)
|
||||
return False, []
|
||||
|
||||
|
||||
@register()
|
||||
class update_krb_uri_txt_records_for_locations(DNSUpdater):
|
||||
|
||||
backup_filename = u'dns-krb-uri-txt-records-for-locations-%Y-%m-%d-%H-%M-'\
|
||||
u'%S.ldif'
|
||||
|
||||
def execute(self, **options):
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
if not dns_container_exists(ldap):
|
||||
return False, []
|
||||
|
||||
locations = []
|
||||
|
||||
for location in self.api.Command.location_find()['result']:
|
||||
locations.append(str(location['idnsname'][0]))
|
||||
|
||||
if not locations:
|
||||
return False, []
|
||||
|
||||
tmpl_class_attr = 'objectClass'
|
||||
tmpl_class_value = 'idnsTemplateObject'
|
||||
cname_tmpl_attr = 'idnsTemplateAttribute;cnamerecord'
|
||||
cname_tmpl_value = '_kerberos.\\{substitutionvariable_ipalocation\\}.'\
|
||||
'_locations'
|
||||
|
||||
domain = self.env.domain
|
||||
realm = self.env.realm
|
||||
|
||||
dns_updates = []
|
||||
|
||||
main_krb_rec = '_kerberos.' + domain + '.'
|
||||
main_krb_rec_dn = DN(('idnsname', '_kerberos'),
|
||||
('idnsname', domain + '.'),
|
||||
self.env.container_dns, self.env.basedn)
|
||||
|
||||
try:
|
||||
entry = ldap.get_entry(main_krb_rec_dn, [
|
||||
tmpl_class_attr, cname_tmpl_attr,
|
||||
])
|
||||
except errors.NotFound:
|
||||
logger.debug('DNS: %s does not exist, there is no %s record to '
|
||||
'convert into CNAME', main_krb_rec_dn, main_krb_rec)
|
||||
else:
|
||||
cname_updates = []
|
||||
|
||||
if tmpl_class_value not in entry.get(tmpl_class_attr, []):
|
||||
logger.debug('DNS: convert %s into a CNAME record',
|
||||
main_krb_rec)
|
||||
cname_updates.append({
|
||||
'action': 'add',
|
||||
'attr': tmpl_class_attr,
|
||||
'value': tmpl_class_value,
|
||||
})
|
||||
|
||||
if cname_tmpl_value not in entry.get(cname_tmpl_attr, []):
|
||||
logger.debug('DNS: update %s CNAME record to point to location '
|
||||
'records', main_krb_rec)
|
||||
cname_updates.append({
|
||||
'action': 'add',
|
||||
'attr': cname_tmpl_attr,
|
||||
'value': cname_tmpl_value,
|
||||
})
|
||||
|
||||
if cname_updates:
|
||||
dns_updates.append({
|
||||
'dn': main_krb_rec_dn,
|
||||
'updates': cname_updates,
|
||||
})
|
||||
else:
|
||||
logger.debug('DNS: %s is already a valid CNAME record',
|
||||
main_krb_rec)
|
||||
|
||||
for location in locations:
|
||||
location_krb_rec = '_kerberos.' + location + '._locations.' \
|
||||
+ domain + '.'
|
||||
location_krb_rec_dn = DN(('idnsname',
|
||||
'_kerberos.' + location + '._locations'),
|
||||
('idnsname', domain + '.'),
|
||||
self.env.container_dns, self.env.basedn)
|
||||
|
||||
try:
|
||||
entry = ldap.get_entry(location_krb_rec_dn, ['tXTRecord'])
|
||||
except errors.NotFound:
|
||||
logger.debug('DNS: %s does not exist, there is no %s URI '
|
||||
'record to rely on to create a TXT record',
|
||||
location_krb_rec_dn, location_krb_rec)
|
||||
else:
|
||||
if 'tXTRecord' in entry:
|
||||
logger.debug('DNS: there already is a %s TXT record',
|
||||
location_krb_rec)
|
||||
else:
|
||||
logger.debug('DNS: add %s location-aware TXT record',
|
||||
location_krb_rec)
|
||||
dns_updates.append({
|
||||
'dn': location_krb_rec_dn,
|
||||
'updates': [
|
||||
{
|
||||
'action': 'addifnew',
|
||||
'attr': 'tXTRecord',
|
||||
'value': f'"{realm}"',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
return False, dns_updates
|
||||
|
||||
@@ -22,6 +22,7 @@ import logging
|
||||
from ipaserver.install import replication
|
||||
from ipalib import Registry
|
||||
from ipalib import Updater
|
||||
from ipalib import errors
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -41,35 +42,42 @@ class update_replica_attribute_lists(Updater):
|
||||
def execute(self, **options):
|
||||
# We need an LDAPClient connection to the backend
|
||||
logger.debug("Start replication agreement exclude list update task")
|
||||
conn = self.api.Backend.ldap2
|
||||
|
||||
repl = replication.ReplicationManager(self.api.env.realm,
|
||||
self.api.env.host,
|
||||
None, conn=conn)
|
||||
|
||||
# We need to update only IPA replica agreements, not winsync
|
||||
ipa_replicas = repl.find_ipa_replication_agreements()
|
||||
|
||||
logger.debug("Found %d agreement(s)", len(ipa_replicas))
|
||||
|
||||
for replica in ipa_replicas:
|
||||
for desc in replica.get('description', []):
|
||||
logger.debug('%s', desc)
|
||||
|
||||
self._update_attr(repl, replica,
|
||||
'nsDS5ReplicatedAttributeList',
|
||||
replication.EXCLUDES, template=EXCLUDE_TEMPLATE)
|
||||
self._update_attr(repl, replica,
|
||||
'nsDS5ReplicatedAttributeListTotal',
|
||||
replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE)
|
||||
self._update_attr(repl, replica,
|
||||
'nsds5ReplicaStripAttrs', replication.STRIP_ATTRS)
|
||||
# Find suffixes
|
||||
suffixes = self.api.Command.topologysuffix_find()['result']
|
||||
for suffix in suffixes:
|
||||
suffix_name = suffix['cn'][0]
|
||||
# Find segments
|
||||
sgmts = self.api.Command.topologysegment_find(
|
||||
suffix_name, all=True)['result']
|
||||
for segment in sgmts:
|
||||
updates = {}
|
||||
updates = self._update_attr(
|
||||
segment, updates,
|
||||
'nsds5replicatedattributelist',
|
||||
replication.EXCLUDES, template=EXCLUDE_TEMPLATE)
|
||||
updates = self._update_attr(
|
||||
segment, updates,
|
||||
'nsds5replicatedattributelisttotal',
|
||||
replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE)
|
||||
updates = self._update_attr(
|
||||
segment, updates,
|
||||
'nsds5replicastripattrs', replication.STRIP_ATTRS)
|
||||
if updates:
|
||||
try:
|
||||
self.api.Command.topologysegment_mod(
|
||||
suffix_name, segment['cn'][0],
|
||||
**updates)
|
||||
except errors.EmptyModlist:
|
||||
# No update done
|
||||
logger.debug("No update required for the segment %s",
|
||||
segment['cn'][0])
|
||||
|
||||
logger.debug("Done updating agreements")
|
||||
|
||||
return False, [] # No restart, no updates
|
||||
|
||||
def _update_attr(self, repl, replica, attribute, values, template='%s'):
|
||||
def _update_attr(self, segment, updates, attribute, values, template='%s'):
|
||||
"""Add or update an attribute of a replication agreement
|
||||
|
||||
If the attribute doesn't already exist, it is added and set to
|
||||
@@ -77,27 +85,21 @@ class update_replica_attribute_lists(Updater):
|
||||
If the attribute does exist, `values` missing from it are just
|
||||
appended to the end, also space-separated.
|
||||
|
||||
:param repl: Replication manager
|
||||
:param replica: Replica agreement
|
||||
:param: updates: dict containing the updates
|
||||
:param segment: dict containing segment information
|
||||
:param attribute: Attribute to add or update
|
||||
:param values: List of values the attribute should hold
|
||||
:param template: Template to use when adding attribute
|
||||
"""
|
||||
attrlist = replica.single_value.get(attribute)
|
||||
attrlist = segment.get(attribute)
|
||||
if attrlist is None:
|
||||
logger.debug("Adding %s", attribute)
|
||||
|
||||
# Need to add it altogether
|
||||
replica[attribute] = [template % " ".join(values)]
|
||||
|
||||
try:
|
||||
repl.conn.update_entry(replica)
|
||||
logger.debug("Updated")
|
||||
except Exception as e:
|
||||
logger.error("Error caught updating replica: %s", str(e))
|
||||
updates[attribute] = template % " ".join(values)
|
||||
|
||||
else:
|
||||
attrlist_normalized = attrlist.lower().split()
|
||||
attrlist_normalized = attrlist[0].lower().split()
|
||||
missing = [a for a in values
|
||||
if a.lower() not in attrlist_normalized]
|
||||
|
||||
@@ -105,14 +107,8 @@ class update_replica_attribute_lists(Updater):
|
||||
logger.debug("%s needs updating (missing: %s)", attribute,
|
||||
', '.join(missing))
|
||||
|
||||
replica[attribute] = [
|
||||
'%s %s' % (attrlist, ' '.join(missing))]
|
||||
updates[attribute] = '%s %s' % (attrlist[0], ' '.join(missing))
|
||||
|
||||
try:
|
||||
repl.conn.update_entry(replica)
|
||||
logger.debug("Updated %s", attribute)
|
||||
except Exception as e:
|
||||
logger.error("Error caught updating %s: %s",
|
||||
attribute, str(e))
|
||||
else:
|
||||
logger.debug("%s: No update necessary", attribute)
|
||||
return updates
|
||||
|
||||
@@ -32,10 +32,7 @@ class update_ca_topology(Updater):
|
||||
logger.debug("CA is not configured on this host")
|
||||
return False, []
|
||||
|
||||
ld = ldapupdate.LDAPUpdate(ldapi=True, sub_dict={
|
||||
'SUFFIX': self.api.env.basedn,
|
||||
'FQDN': self.api.env.host,
|
||||
})
|
||||
ld = ldapupdate.LDAPUpdate(api=self.api)
|
||||
|
||||
ld.update([paths.CA_TOPOLOGY_ULDIF])
|
||||
|
||||
|
||||
@@ -15,73 +15,92 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
register = Registry()
|
||||
|
||||
|
||||
@register()
|
||||
class update_dna_shared_config(Updater):
|
||||
def execute(self, **options):
|
||||
method = options.get('method', "SASL/GSSAPI")
|
||||
protocol = options.get('protocol', "LDAP")
|
||||
dna_plugin_names = ('posix IDs', 'Subordinate IDs')
|
||||
|
||||
dna_bind_method = "dnaRemoteBindMethod"
|
||||
dna_conn_protocol = "dnaRemoteConnProtocol"
|
||||
dna_plugin = DN(('cn', 'Distributed Numeric Assignment Plugin'),
|
||||
('cn', 'plugins'),
|
||||
('cn', 'config'))
|
||||
dna_config_base = DN(('cn', 'posix IDs'), dna_plugin)
|
||||
dna_plugin_dn = DN(
|
||||
('cn', 'Distributed Numeric Assignment Plugin'),
|
||||
('cn', 'plugins'),
|
||||
('cn', 'config')
|
||||
)
|
||||
|
||||
conn = self.api.Backend.ldap2
|
||||
def is_dna_enabled(self):
|
||||
"""Check the plugin is enabled
|
||||
|
||||
# Check the plugin is enabled else it is useless to update
|
||||
# the shared entry
|
||||
Else it is useless to update the shared entry
|
||||
"""
|
||||
try:
|
||||
entry = conn.get_entry(dna_plugin)
|
||||
if entry.single_value.get('nsslapd-pluginenabled') == 'off':
|
||||
return False, ()
|
||||
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",
|
||||
dna_config_base)
|
||||
return False, ()
|
||||
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 = conn.get_entry(dna_config_base)
|
||||
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 False, ()
|
||||
return None
|
||||
|
||||
#
|
||||
# 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 60s before logging
|
||||
# the failure to update the shared config entry and return
|
||||
#
|
||||
max_wait = 30
|
||||
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
|
||||
)
|
||||
break
|
||||
# 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 "
|
||||
@@ -94,35 +113,35 @@ class update_dna_shared_config(Updater):
|
||||
"Could not get dnaHostname entries in %s seconds",
|
||||
max_wait * 2
|
||||
)
|
||||
return False, ()
|
||||
|
||||
# If there are several entries, all of them will be updated
|
||||
# just log a debug msg. This is likely the result of #5510
|
||||
if len(entries) != 1:
|
||||
logger.debug(
|
||||
"%d entries dnaHostname=%s under %s. One expected",
|
||||
len(entries), fqdn, sharedcfgdn
|
||||
)
|
||||
return False
|
||||
|
||||
# time to set the bind method and the protocol in the
|
||||
# shared config entries
|
||||
for entry in entries:
|
||||
update = False
|
||||
if entry.single_value.get(dna_bind_method) != method:
|
||||
entry[dna_bind_method] = method
|
||||
update = True
|
||||
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)
|
||||
|
||||
if entry.single_value.get(dna_conn_protocol) != protocol:
|
||||
entry[dna_conn_protocol] = protocol
|
||||
update = True
|
||||
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)
|
||||
|
||||
if update:
|
||||
try:
|
||||
conn.update_entry(entry)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to set SASL/GSSAPI bind method/protocol "
|
||||
"in entry %s: %s", entry, e
|
||||
)
|
||||
# no restart, no update
|
||||
return False, ()
|
||||
|
||||
@@ -51,7 +51,7 @@ class update_idrange_type(Updater):
|
||||
(entries, truncated) = ldap.find_entries(search_filter,
|
||||
['objectclass'], base_dn, time_limit=0, size_limit=0)
|
||||
|
||||
except errors.NotFound:
|
||||
except errors.EmptyResult:
|
||||
logger.debug("update_idrange_type: no ID range without "
|
||||
"type set found")
|
||||
return False, []
|
||||
@@ -61,11 +61,6 @@ class update_idrange_type(Updater):
|
||||
"of ranges with no type set: %s", e)
|
||||
return False, []
|
||||
|
||||
if not entries:
|
||||
# No entry was returned, rather break than continue cycling
|
||||
logger.debug("update_idrange_type: no ID range was returned")
|
||||
return False, []
|
||||
|
||||
logger.debug("update_idrange_type: found %d "
|
||||
"idranges to update, truncated: %s",
|
||||
len(entries), truncated)
|
||||
|
||||
@@ -661,14 +661,14 @@ class update_managed_permissions(Updater):
|
||||
# Exclude attributes filtered from the global read ACI
|
||||
replaces_ga_aci = template.pop('replaces_global_anonymous_aci', False)
|
||||
if replaces_ga_aci and is_new and anonymous_read_aci:
|
||||
read_blacklist = set(
|
||||
read_blocklist = set(
|
||||
a.lower() for a in
|
||||
anonymous_read_aci.target['targetattr']['expression'])
|
||||
read_blacklist &= attributes
|
||||
if read_blacklist:
|
||||
read_blocklist &= attributes
|
||||
if read_blocklist:
|
||||
logger.debug('Excluded attributes for %s: %s',
|
||||
name, ', '.join(read_blacklist))
|
||||
entry['ipapermexcludedattr'] = list(read_blacklist)
|
||||
name, ', '.join(read_blocklist))
|
||||
entry['ipapermexcludedattr'] = list(read_blocklist)
|
||||
|
||||
# Sanity check
|
||||
if template:
|
||||
|
||||
@@ -67,7 +67,7 @@ class update_nis_configuration(Updater):
|
||||
True)
|
||||
|
||||
# bug is effective run update to recreate missing maps
|
||||
ld = LDAPUpdate(sub_dict={}, ldapi=True)
|
||||
ld = LDAPUpdate(api=self.api)
|
||||
ld.update([paths.NIS_ULDIF])
|
||||
|
||||
def execute(self, **options):
|
||||
@@ -86,7 +86,7 @@ class update_nis_configuration(Updater):
|
||||
self.__recover_from_missing_maps(ldap)
|
||||
|
||||
logger.debug("Executing NIS Server update")
|
||||
ld = LDAPUpdate(sub_dict={}, ldapi=True)
|
||||
ld = LDAPUpdate(api=self.api)
|
||||
ld.update([paths.NIS_UPDATE_ULDIF])
|
||||
|
||||
return False, ()
|
||||
|
||||
146
ipaserver/install/plugins/update_pwpolicy.py
Normal file
146
ipaserver/install/plugins/update_pwpolicy.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#
|
||||
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
import logging
|
||||
|
||||
from ipalib import Registry, errors
|
||||
from ipalib import Updater
|
||||
from ipapython.dn import DN
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
register = Registry()
|
||||
|
||||
|
||||
@register()
|
||||
class update_pwpolicy(Updater):
|
||||
"""
|
||||
Add new ipapwdpolicy objectclass to all password policies
|
||||
|
||||
Otherwise pwpolicy-find will not find them.
|
||||
"""
|
||||
|
||||
def execute(self, **options):
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
base_dn = DN(('cn', self.api.env.realm), ('cn', 'kerberos'),
|
||||
self.api.env.basedn)
|
||||
search_filter = (
|
||||
"(&(objectClass=krbpwdpolicy)(!(objectclass=ipapwdpolicy)))"
|
||||
)
|
||||
|
||||
while True:
|
||||
# Run the search in loop to avoid issues when LDAP limits are hit
|
||||
# during update
|
||||
|
||||
try:
|
||||
(entries, truncated) = ldap.find_entries(
|
||||
search_filter, ['objectclass'], base_dn, time_limit=0,
|
||||
size_limit=0)
|
||||
|
||||
except errors.EmptyResult:
|
||||
logger.debug("update_pwpolicy: no policies without "
|
||||
"objectclass set")
|
||||
return False, []
|
||||
|
||||
except errors.ExecutionError as e:
|
||||
logger.error("update_pwpolicy: cannot retrieve list "
|
||||
"of policies missing an objectclass: %s", e)
|
||||
return False, []
|
||||
|
||||
logger.debug("update_pwpolicy: found %d "
|
||||
"policies to update, truncated: %s",
|
||||
len(entries), truncated)
|
||||
|
||||
error = False
|
||||
|
||||
for entry in entries:
|
||||
entry['objectclass'].append('ipapwdpolicy')
|
||||
try:
|
||||
ldap.update_entry(entry)
|
||||
except (errors.EmptyModlist, errors.NotFound):
|
||||
pass
|
||||
except errors.ExecutionError as e:
|
||||
logger.debug("update_pwpolicy: cannot "
|
||||
"update policy: %s", e)
|
||||
error = True
|
||||
|
||||
if error:
|
||||
# Exit loop to avoid infinite cycles
|
||||
logger.error("update_pwpolicy: error(s) "
|
||||
"detected during pwpolicy update")
|
||||
return False, []
|
||||
|
||||
elif not truncated:
|
||||
# All affected entries updated, exit the loop
|
||||
logger.debug("update_pwpolicy: all policies updated")
|
||||
return False, []
|
||||
|
||||
return False, []
|
||||
|
||||
|
||||
@register()
|
||||
class update_pwpolicy_grace(Updater):
|
||||
"""
|
||||
Ensure all group policies have a grace period set.
|
||||
"""
|
||||
|
||||
def execute(self, **options):
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
base_dn = DN(('cn', self.api.env.realm), ('cn', 'kerberos'),
|
||||
self.api.env.basedn)
|
||||
search_filter = (
|
||||
"(&(objectClass=krbpwdpolicy)(!(passwordgracelimit=*)))"
|
||||
)
|
||||
|
||||
while True:
|
||||
# Run the search in loop to avoid issues when LDAP limits are hit
|
||||
# during update
|
||||
|
||||
try:
|
||||
(entries, truncated) = ldap.find_entries(
|
||||
search_filter, ['objectclass'], base_dn, time_limit=0,
|
||||
size_limit=0)
|
||||
|
||||
except errors.EmptyResult:
|
||||
logger.debug("update_pwpolicy: no policies without "
|
||||
"passwordgracelimit set")
|
||||
return False, []
|
||||
|
||||
except errors.ExecutionError as e:
|
||||
logger.error("update_pwpolicy: cannot retrieve list "
|
||||
"of policies missing passwordgracelimit: %s", e)
|
||||
return False, []
|
||||
|
||||
logger.debug("update_pwpolicy: found %d "
|
||||
"policies to update, truncated: %s",
|
||||
len(entries), truncated)
|
||||
|
||||
error = False
|
||||
|
||||
for entry in entries:
|
||||
# Set unlimited BIND by default
|
||||
entry['passwordgracelimit'] = -1
|
||||
try:
|
||||
ldap.update_entry(entry)
|
||||
except (errors.EmptyModlist, errors.NotFound):
|
||||
pass
|
||||
except errors.ExecutionError as e:
|
||||
logger.debug("update_pwpolicy: cannot "
|
||||
"update policy: %s", e)
|
||||
error = True
|
||||
|
||||
if error:
|
||||
# Exit loop to avoid infinite cycles
|
||||
logger.error("update_pwpolicy: error(s) "
|
||||
"detected during pwpolicy update")
|
||||
return False, []
|
||||
|
||||
elif not truncated:
|
||||
# All affected entries updated, exit the loop
|
||||
logger.debug("update_pwpolicy: all policies updated")
|
||||
return False, []
|
||||
|
||||
return False, []
|
||||
@@ -33,7 +33,14 @@ class update_ra_cert_store(Updater):
|
||||
if not ca_enabled:
|
||||
return False, []
|
||||
|
||||
certdb = NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR)
|
||||
try:
|
||||
certdb = NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR)
|
||||
except ValueError as e:
|
||||
logger.warning("Problem opening NSS database in "
|
||||
"%s. Skipping check for existing RA "
|
||||
"agent certificate: %s", paths.HTTPD_ALIAS_DIR, e)
|
||||
return False, []
|
||||
|
||||
if not certdb.has_nickname(ra_nick):
|
||||
# Nothign to do
|
||||
return False, []
|
||||
|
||||
Reference in New Issue
Block a user