Within a freeipa environment, the syncrepl plugin sometimes provides a wrong cookie 4294967295 and triggers syncrepl_entry callback for a change that should not.
Launch the attached python script to create a refreshAndPersist query:
python test_syncrepl.py
In another window, add a new ipa user:
echo $PASSWORD | kinit admin
ipa user-add testuser --first test --last user
#### Actual results
The script displays the callbacks triggered by syncrepl:
syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test
Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))57
syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test
Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))57
syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test
Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))57
syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test
Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))59
syncrepl_entry dn cn=ipausers,cn=groups,cn=accounts,dc=ipa,dc=test
Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))4294967295
#### Expected results
The last cookie with changenumber 4294967295 is invalid. It looks like it corresponds to the creation of IPA private group for the user, that has objectclasses `top`, `mepManagedEntry`, `ipaobject` and `posixgroup`.
I would not expect the private group creation to trigger the syncrepl callback `syncrepl_entry`, as it does not contain the objectclass groupofnames that is specified in the filterstr.
Script:
cat test_syncrepl.py
import ldap
import ldapurl
from ldap.syncrepl import SyncreplConsumer
from ldap.ldapobject import ReconnectLDAPObject
import os
import pwd
import sys
from ipalib import api
from ipaplatform.paths import paths
from ipapython.dn import DN
Cloned from Pagure issue: https://pagure.io/389-ds-base/issue/51190
Issue Description
Within a freeipa environment, the syncrepl plugin sometimes provides a wrong cookie 4294967295 and triggers syncrepl_entry callback for a change that should not.
Package Version and Platform
Fedora 32 with: 389-ds-base-1.4.3.10-1.fc32.x86_64 freeipa-server-4.8.7-1.fc32.x86_64
Steps to reproduce
ipa-server-install --domain ipa.test --realm IPA.TEST --setup-dns --auto-forwarder --auto-reverse -a $PASSWORD -p $PASSWORD -U
EOF
systemctl restart dirsrv@IPA-TEST.service
python test_syncrepl.py
echo $PASSWORD | kinit admin ipa user-add testuser --first test --last user
syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))57 syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))57 syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))57 syncrepl_entry dn uid=testuser,cn=users,cn=accounts,dc=ipa,dc=test Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))59 syncrepl_entry dn cn=ipausers,cn=groups,cn=accounts,dc=ipa,dc=test Set cookie: master.ipa.test:389#cn=Directory Manager:cn=accounts,dc=ipa,dc=test:(|(objectClass=groupofnames)(objectClass=person))4294967295
cat test_syncrepl.py
import ldap import ldapurl from ldap.syncrepl import SyncreplConsumer from ldap.ldapobject import ReconnectLDAPObject import os import pwd import sys
from ipalib import api from ipaplatform.paths import paths from ipapython.dn import DN
class TestSyncer(ReconnectLDAPObject, SyncreplConsumer): def init(self, *args, *kwargs): self.cookie = None ldap.ldapobject.ReconnectLDAPObject.init(self, args, **kwargs)
if len(sys.argv) >= 2: cookie = sys.argv[1] else: cookie = None
api.bootstrap( in_server=True, context='test_syncrepl', confdir=paths.ETC_IPA, log=None ) api.finalize()
basedn = DN(api.env.container_accounts, api.env.basedn) ldap_url = ldapurl.LDAPUrl(api.env.ldap_uri) ldap_url.dn = str(basedn) ldap_url.scope = ldapurl.LDAP_SCOPE_SUBTREE ldap_url.filterstr = '(|(objectClass=groupofnames)(objectClass=person))' ldap_url.attrs = [ 'objectclass', 'cn', 'displayname', 'gidnumber', 'givenname', 'homedirectory', 'ipaexternalmember', 'ipantsecurityidentifier', 'ipauniqueid', 'krbcanonicalname', 'krbprincipalname', 'mail', 'member', 'memberof', 'sn', 'uid', 'uidnumber', ]
ldap_connection = TestSyncer(ldap_url.initializeUrl()) user_name = pwd.getpwuid(os.geteuid()).pw_name auth_tokens = ldap.sasl.external(user_name) ldap_connection.sasl_interactive_bind_s('', auth_tokens)
ldap_search = ldap_connection.syncrepl_search( ldap_url.dn, ldap_url.scope, mode='refreshAndPersist', attrlist=ldap_url.attrs, filterstr=ldap_url.filterstr, cookie=cookie )
try: while ldap_connection.syncrepl_poll(all=1, msgid=ldap_search): pass except (ldap.SERVER_DOWN, ldap.CONNECT_ERROR) as e: print('syncrepl_poll: LDAP error (%s)', e) sys.exit(1)