diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2025-01-30 00:58:13 +0100 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2025-02-01 13:56:14 +0100 |
commit | f647dd2265bf4c5a2903325f628774eace2011ce (patch) | |
tree | 715821c697ba3988acf93626645b943df2ee2bdd /lib/modules/openldap | |
parent | bcdb01c02f392503c91538b3c1fabe62544ef423 (diff) |
LDAP: Load dynlist overlay.
Looks like nextcloud 26-29 broke something in the handling of dynamic
groups via memberURL attribute (and keeps repopulating the group —
possibly due to paging — thereby spamming members with “An administrator
removed you from group medlemmar” mails), so we expand on the slapd via
slapo-dynlist(5) instead.
This commit also fixes an issue with the openldap module where the index
of the leftmost attribute of the DN is not necessary {0}.
Diffstat (limited to 'lib/modules/openldap')
-rw-r--r-- | lib/modules/openldap | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/lib/modules/openldap b/lib/modules/openldap index c09e791..f24a802 100644 --- a/lib/modules/openldap +++ b/lib/modules/openldap @@ -21,40 +21,41 @@ from ldap.filter import filter_format from ldap.dn import dn2str,explode_dn,str2dn from ldap.modlist import addModlist from ldif import LDIFParser from functools import partial import re, pwd import tempfile, atexit # Dirty hack to check equality between the targetted LDIF and that # currently in the directory. The value of some configuration (olc*) # attributes is automatically indexed when added; for those we'll add # explicit indices to what we find in the LDIF. indexedAttributes = frozenset([ 'olcAttributeTypes', 'olcObjectClasses', 'olcAccess', 'olcSyncrepl', 'olcOverlay', 'olcLimits', 'olcAuthzRegexp', + 'olcDlAttrSet', 'olcDbConfig', ]) # Another hack. Configuration entries sometimes pollutes the DNs with # indices, thus it's not possible to directly use them as base. # Instead, we use their parent as a base, and search for the *unique* # match with the same ObjectClass and the matching extra attributes. # ('%s' in the attribute value is replaced with the value of the source # entry.) indexedDN = { b'olcSchemaConfig': [('cn', '{*}%s')], b'olcMdbConfig': [('olcDbDirectory', '%s' )], b'olcOverlayConfig': [('olcOverlay', '%s' )], b'olcMonitorConfig': [], } # Allow for flexible ACLs for user using SASL's EXTERNAL mechanism. # "username=postfix,cn=peercred,cn=external,cn=auth" is replaced by # "gidNumber=106+uidNumber=102,cn=peercred,cn=external,cn=auth" where @@ -139,57 +140,69 @@ def processEntry(module, l, dn, entry): for x in indexedAttributes.intersection(entry.keys()): # remove useless extra spaces in ACLs etc entry[x] = list(map( partial(multispaces.sub, b' '), entry[x] )) r = flexibleSearch( module, l, dn, entry ) if r is None: changed = True if module.check_mode: module.exit_json(changed=changed, msg="add DN %s" % dn) if 'olcAccess' in entry.keys(): # replace "username=...,cn=peercred,cn=external,cn=auth" # by a DN with proper gidNumber and uidNumber entry['olcAccess'] = list(map ( partial(sasl_ext_re.sub, acl_sasl_ext) , entry['olcAccess'] )) l.add_s( dn, addModlist(entry) ) else: d,e = r fst = str2dn(dn).pop(0)[0][0] diff = [] + re1 = re.compile( b'^(\{[0-9]+\})', re.I ) for a,v in e.items(): if a not in entry.keys(): if a != fst: # delete all values except for the first attribute, # which is implicit diff.append(( ldap.MOD_DELETE, a, None )) elif a in indexedAttributes: if a == 'olcAccess': # replace "username=...,cn=peercred,cn=external,cn=auth" # by a DN with proper gidNumber and uidNumber entry[a] = list(map ( partial(sasl_ext_re.sub, acl_sasl_ext) , entry[a] )) - # add explicit indices in the entry from the LDIF - entry[a] = list(map( (lambda x: b'{%d}%s' % x) - , zip(range(len(entry[a])),entry[a]))) - if v != entry[a]: - diff.append(( ldap.MOD_REPLACE, a, entry[a] )) + if a == fst: + if len(entry[a]) != 1 or len(v) != 1: + module.fail_json(msg=f'{len(entry[a])} != 1 or {len(v)} != 1') + m1 = re1.match(v[0]) + if m1 is None: + module.fail_json(msg=f'{v[0]} is not indexed??') + else: + entry[a][0] = m1.group(1) + entry[a][0] + if entry[a] != v: + module.fail_json(msg=f'{entry[a]} != {v}, use modrdn to modifify the RDN (unimplemented)') + else: + # add explicit indices in the entry from the LDIF + entry[a] = list(map( (lambda x: b'{%d}%s' % x) + , zip(range(len(entry[a])),entry[a]))) + if v != entry[a]: + diff.append(( ldap.MOD_REPLACE, a, entry[a] )) elif v != entry[a]: # for non-indexed attribute, we update values in the # symmetric difference only s1 = set(v) s2 = set(entry[a]) if s1.isdisjoint(s2): # replace the former values with the new ones diff.append(( ldap.MOD_REPLACE, a, entry[a] )) else: x = list(s1.difference(s2)) if x: diff.append(( ldap.MOD_DELETE, a, x )) y = list(s2.difference(s1)) if y: diff.append(( ldap.MOD_ADD, a, y )) # add attributes that weren't in e for a in set(entry).difference(e.keys()): diff.append(( ldap.MOD_ADD, a, entry[a] )) |