From 00abd47de4d3238295cbe5dc30210b913c0f07a1 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 19 May 2011 22:30:53 -0400 Subject: Enable 389-ds SSL host checking by defauilt Enforce that the remote hostname matches the remote SSL server certificate when 389-ds operates as an SSL client. Also add an update file to turn this off for existing installations. This also changes the way the ldapupdater modlist is generated to be more like the framework. Single-value attributes are done as replacements and there is a list of force-replacement attributes. ticket 1069 --- ipaserver/install/dsinstance.py | 3 +-- ipaserver/ipaldap.py | 57 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 8 deletions(-) (limited to 'ipaserver') diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index 74243cfc1..229e14282 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -541,8 +541,7 @@ class DsInstance(service.Service): +tls_rsa_export1024_with_des_cbc_sha")] conn.modify_s("cn=encryption,cn=config", mod) - mod = [(ldap.MOD_ADD, "nsslapd-security", "on"), - (ldap.MOD_REPLACE, "nsslapd-ssl-check-hostname", "off")] + mod = [(ldap.MOD_ADD, "nsslapd-security", "on")] conn.modify_s("cn=config", mod) entry = ipaldap.Entry("cn=RSA,cn=encryption,cn=config") diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py index 7df7cceff..cf76d6222 100644 --- a/ipaserver/ipaldap.py +++ b/ipaserver/ipaldap.py @@ -247,6 +247,7 @@ class IPAdmin(SimpleLDAPObject): self.ldapi = ldapi self.realm = realm self.suffixes = {} + self.schema = None self.__localinit() def __lateinit(self): @@ -497,8 +498,13 @@ class IPAdmin(SimpleLDAPObject): def generateModList(self, old_entry, new_entry): """A mod list generator that computes more precise modification lists - than the python-ldap version. This version purposely generates no - REPLACE operations, to deal with multi-user updates more properly.""" + than the python-ldap version. For single-value attributes always + use a REPLACE operation, otherwise use ADD/DEL. + """ + + # Some attributes, like those in cn=config, need to be replaced + # not deleted/added. + FORCE_REPLACE_ON_UPDATE_ATTRS = ('nsslapd-ssl-check-hostname',) modlist = [] old_entry = ipautil.CIDict(old_entry) @@ -523,16 +529,28 @@ class IPAdmin(SimpleLDAPObject): adds = list(new_values.difference(old_values)) removes = list(old_values.difference(new_values)) + if len(adds) == 0 and len(removes) == 0: + continue + + is_single_value = self.get_single_value(key) + force_replace = False + if key in FORCE_REPLACE_ON_UPDATE_ATTRS or is_single_value: + force_replace = True + # You can't remove schema online. An add will automatically # replace any existing schema. if old_entry.get('dn') == 'cn=schema': if len(adds) > 0: modlist.append((ldap.MOD_ADD, key, adds)) else: - if len(removes) > 0: - modlist.append((ldap.MOD_DELETE, key, removes)) - if len(adds) > 0: - modlist.append((ldap.MOD_ADD, key, adds)) + if adds: + if force_replace: + modlist.append((ldap.MOD_REPLACE, key, adds)) + else: + modlist.append((ldap.MOD_ADD, key, adds)) + if removes: + if not force_replace: + modlist.append((ldap.MOD_DELETE, key, removes)) return modlist @@ -664,6 +682,33 @@ class IPAdmin(SimpleLDAPObject): else: break return (done, exitCode) + def get_schema(self): + """ + Retrieve cn=schema and convert it into a python-ldap schema + object. + """ + if self.schema: + return self.schema + schema = self.getEntry('cn=schema', ldap.SCOPE_BASE, + '(objectclass=*)', ['attributetypes', 'objectclasses']) + schema = schema.toDict() + self.schema = ldap.schema.SubSchema(schema) + return self.schema + + def get_single_value(self, attr): + """ + Check the schema to see if the attribute is single-valued. + + If the attribute is in the schema then returns True/False + + If there is a problem loading the schema or the attribute is + not in the schema return None + """ + if not self.schema: + self.get_schema() + obj = self.schema.get_obj(ldap.schema.AttributeType, attr) + return obj and obj.single_value + def normalizeDN(dn): # not great, but will do until we use a newer version of python-ldap # that has DN utilities -- cgit