Issue 8686 - modrdn can't find the target dn if it is read directly from hdb backend
Summary: modrdn can't find the target dn if it is read directly from hdb backend
Status: VERIFIED WONTFIX
Alias: None
Product: OpenLDAP
Classification: Unclassified
Component: slapd (show other issues)
Version: 2.4.44
Hardware: All All
: --- normal
Target Milestone: ---
Assignee: OpenLDAP project
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-07-07 06:44 UTC by yoshiho.yoshida@synacor.com
Modified: 2020-03-23 15:50 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description yoshiho.yoshida@synacor.com 2017-07-07 06:44:13 UTC
Full_Name: Yoshiho Yoshida
Version: 2.4.44
OS: CentOS 6.5
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (210.237.186.4)


This issue only happens with hdb back-end database.
If the target dn is not in the cache memory, then modrdn tries to get it from
hdb using its normalized rdn.
As this result, modrdn can't find the target dn with "No such attribute (16)" or
"No such object (32)" error.

  no cache --> dn2id.bdb -- id -->  id2entry.bdb

The problem seems to exist in the buffer size to get id from dn2id.bdb.

Test case uses uid as rdn and its syntax is SYNTAX
1.3.6.1.4.1.1466.115.121.1.15{256} .
Then this normalize is,
  1) Normalization of UTF-8 (NKFC mormalization)
  2) consecutive space characters to a single space
  3) trim the ending space

If the size of original rdn and normalized rdn is as follows, this problem
occurs.

len_rdn is the size of original rdn.
len_norm_rdn is the size of normalized rdn.

((3 + len_norm_rdn) * 3) less than equal to ((3 + len_norm_rdn) + 1 + len_rdn +
1 + 8)

Test case:

1. Test data

$ cat zzz.ldif
dn: dc=zzz
dc: zzz
objectClass: dcObject
objectClass: organization
o: zzz domain

$ cat yyy.ldif
dn: dc=yyy,dc=zzz
o: yyy.zzz domain
objectClass: dcObject
objectClass: organization
dc: yyy

$ cat people.ldif
dn: ou=people,dc=yyy,dc=zzz
ou: people
objectClass: organizationalRole
cn: people

$ cat xxx.ldif
dn: uid=xxx,ou=people,dc=yyy,dc=zzz
sn: xxx
cn: xxx
uid: xxx
objectClass: inetOrgPerson

$ 

2. Add the above test data into ldap database (hdb)

$ ldapadd -v -x -h 192.168.10.131 -D'uid=zimbra,cn=admins,cn=zimbra' -w password
-f zzz.ldif
ldap_initialize( ldap://192.168.10.131 )
add dc:
        zzz
add objectClass:
        dcObject
        organization
add o:
        zzz domain
adding new entry "dc=zzz"
modify complete

$ ldapadd -v -x -h 192.168.10.131 -D'uid=zimbra,cn=admins,cn=zimbra' -w password
-f yyy.ldif
ldap_initialize( ldap://192.168.10.131 )
add o:
        yyy.zzz domain
add objectClass:
        dcObject
        organization
add dc:
        yyy
adding new entry "dc=yyy,dc=zzz"
modify complete

$ ldapadd -v -x -h 192.168.10.131 -D'uid=zimbra,cn=admins,cn=zimbra' -w password
-f people.ldif
ldap_initialize( ldap://192.168.10.131 )
add ou:
        people
add objectClass:
        organizationalRole
add cn:
        people
adding new entry "ou=people,dc=yyy,dc=zzz"
modify complete

$ ldapadd -v -x -h 192.168.10.131 -D'uid=zimbra,cn=admins,cn=zimbra' -w password
-f xxx.ldif
ldap_initialize( ldap://192.168.10.131 )
add sn:
        xxx
add cn:
        xxx
add uid:
        xxx
add objectClass:
        inetOrgPerson
adding new entry "uid=xxx,ou=people,dc=yyy,dc=zzz"
modify complete

$ 

o Verify the added dn

$ ldapsearch -LL -x -h 192.168.10.131 -D 'uid=zimbra,cn=admins,cn=zimbra' -w
password uid=xxx
version: 1

dn: uid=xxx,ou=people,dc=yyy,dc=zzz
sn: xxx
cn: xxx
uid: xxx
objectClass: inetOrgPerson

$ 

3. modify the above dn (rdn)

$ cat modrdn_1.ldif
uid=xxx,ou=people,dc=yyy,dc=zzz
uid=\20a

$ 

$ ldapmodrdn -v -x -r -h 192.168.10.131 -p 389 -D
'uid=zimbra,cn=admins,cn=zimbra' -w password -f modrdn_1.ldif
ldap_initialize( ldap://192.168.10.131:389 )
Renaming "uid=xxx,ou=people,dc=yyy,dc=zzz"
        new rdn="uid=\20a" (delete old rdn)
Rename Result: Success (0)
$ 

o Verify the changed rdn

$ ldapsearch -LL -x -h 192.168.10.131 -D 'uid=zimbra,cn=admins,cn=zimbra' -w
password "uid= a"
version: 1

dn: uid=\20a,ou=people,dc=yyy,dc=zzz
sn: xxx
cn: xxx
objectClass: inetOrgPerson
uid:: IGE=

$ 

o Start the recurrence test

4. Restart the slapd to remove the cache

$ ldap stop
Killing slapd with pid 15740 done.
$ 

$ tail /var/log/zimbra.log
Jul  7 12:53:46 jpzcserv1 slapd[15740]: conn=1002 fd=18 closed (slapd shutdown)
Jul  7 12:53:46 jpzcserv1 slapd[15740]: conn=1003 fd=20 closed (slapd shutdown)
Jul  7 12:53:46 jpzcserv1 slapd[15740]: conn=1004 fd=22 closed (slapd shutdown)
Jul  7 12:53:46 jpzcserv1 slapd[15740]: conn=1005 fd=24 closed (slapd shutdown)
Jul  7 12:53:46 jpzcserv1 slapd[15740]: slapd shutdown: waiting for 0
operations/tasks to finish
Jul  7 12:53:46 jpzcserv1 slapd[15740]: slapd stopped.
$ 

$ ldap start
Started slapd: pid 16998
$ 
$ tail /var/log/zimbra.log
Jul  7 12:54:58 jpzcserv1 slapd[16997]: @(#) $OpenLDAP: slapd 2.4.44 (May 30
2017 23:19:56) $#012#011root@jpzcserv1.zimbra.jp:/home/yyoshida/zimbra/work/OpenLDAP_244/openldap-2.4.44/servers/slapd
Jul  7 12:54:58 jpzcserv1 slapd[16998]: slapd starting
$ 

5. Then try to modify the rdn

$ cat modrdn_2.ldif
uid=\20a,ou=people,dc=yyy,dc=zzz
uid=abc
$ 

$ ldapmodrdn -v -x -r -h 192.168.10.131 -p 389 -D
'uid=zimbra,cn=admins,cn=zimbra' -w password -f modrdn_2.ldif
ldap_initialize( ldap://192.168.10.131:389 )
Renaming "uid=\20a,ou=people,dc=yyy,dc=zzz"
        new rdn="uid=abc" (delete old rdn)
Rename Result: No such attribute (16)
Additional info: modify/delete: uid: no such attribute
$ 

Failed with " No such attribute (16)"

6. Then search the target dn to load the entry to cache

$ ldapsearch -LL -x -h 192.168.10.131 -D 'uid=zimbra,cn=admins,cn=zimbra' -w
password "uid= a"
version: 1

dn: uid=\20a,ou=people,dc=yyy,dc=zzz
sn: xxx
cn: xxx
objectClass: inetOrgPerson
uid:: IGE=

$ 

7. Again modify the same rdn

$ ldapmodrdn -v -x -r -h 192.168.10.131 -p 389 -D
'uid=zimbra,cn=admins,cn=zimbra' -w password -f modrdn_2.ldif
ldap_initialize( ldap://192.168.10.131:389 )
Renaming "uid=\20a,ou=people,dc=yyy,dc=zzz"
        new rdn="uid=abc" (delete old rdn)
Rename Result: Success (0)
$ 

Now it can be modified successfully.

This problem found when the replica server needed to be restarted and it never
synchronized with the master server
because there are some bad dn data. The master server is also possible to have
this problem if it needs to be restarted.

Workaround)
 dn2id.c
 increase the size of data.ulen in hdb_dn2id()

    data.ulen = data.size * 3; 
    d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );




Comment 1 yoshiho.yoshida@synacor.com 2017-07-10 10:43:06 UTC
I reported the caluculation of the size of original and normalized rdn is
as follows.

> len_rdn is the size of original rdn.
> len_norm_rdn is the size of normalized rdn.
> 
> ((3 + len_norm_rdn) * 3) less than equal to ((3 + len_norm_rdn) + 1 + len_rdn + 1 + 8)

But after the test about verious sizes of rdn, the above calculation
does not cover the all cases and the next simple calculation should
match more verious sizes.

  len_rdn + 3 > len_norm_rdn x 2

--
Yoshiho Yoshida



This message and any attachment may contain information that is confidential and/or proprietary. Any use, disclosure, copying, storing, or distribution of this e-mail or any attached file by anyone other than the intended recipient is strictly prohibited. If you have received this message in error, please notify the sender by reply email and delete the message and any attachments. Thank you.

Comment 2 Quanah Gibson-Mount 2020-03-23 15:49:55 UTC
back-hdb is deprecated for 2.4, removed for 2.5