[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: back-ldbm/modrdn.c corrupts dn2id.gdbm (ITS#3059)



Your analysis is correct.  I've committed a patch based upon
your suggestion to HEAD.  Please test.

I note that adding the entry with a new ID might be a better
(safer) solution, but I do not have the time nor energy to
look into that.  I'll leave that to others.

Kurt

At 04:30 AM 4/6/2004, wout@science.uva.nl wrote:
>Full_Name: Wout van Albada
>Version: 2.2.6
>OS: Solaris 9
>URL: ftp://ftp.openldap.org/incoming/
>Submission from: (NULL) (146.50.3.34)
>
>
>The back-ldbm backend has a bug in the modify DN operation
>which results in entries remaining in the tree but disappearing
>from ancestral subtrees.
>
>Example:
>
>My suffix is:
>    dc=science,dc=uva,dc=nl
>
>My tree has several branches, one being:
>    ou=ethers,dc=science,dc=uva,dc=nl
>
>I have the following entry:
>    cn=pc-bor19.science.uva.nl,dc=science,dc=uva,dc=nl
>
>When I do a modrdn of the cn attribute, the entry's id
>disappears from the ou=ethers,... subtree and one id lists
>in dn2id.gdbm. This is because of the following code in
>back-ldbm/modrdn.c:
>
>    /* add new one */
>    if ( dn2id_add( op->o_bd, &e->e_nname, e->e_id ) != 0 ) {
>            send_ldap_error( op, rs, LDAP_OTHER,
>                    "DN index add failed" );
>            goto return_results;
>    }
>    /* delete old one */
>    if ( dn2id_delete( op->o_bd, &old_ndn, e->e_id ) != 0 ) {
>            /* undo add of new one */
>            dn2id_delete( op->o_bd, &e->e_nname, e->e_id );
>            send_ldap_error( op, rs, LDAP_OTHER,
>                    "DN index delete fail" );
>            goto return_results;
>    }
>
>The modified entry is first added to dn2id.gdbm using the old
>id of the entry: e->e_id. This means that the id is added to
>the one and subtree id lists for ou=ethers,dc=science,dc=uva,dc=nl.
>
>Then the old entry is removed from dn2id.gdbm using the same
>old id. This means that the id is removed from the one and
>subtree id lists for ou=ethers,dc=science,dc=uva,dc=nl.
>
>Result is the id is no longer in the one and subtree id
>lists for ou=ethers,dc=science,dc=uva,dc=nl.
>
>If the entry was deeper in the tree, more subtrees would be
>corrupted. The subtree for dc=science,dc=uva,dc=nl (suffix)
>does not exist in dn2id.gdbm because it is treated as a
>special case.
>
>The following patch swaps the dn2id_add() and dn2id_delete()
>calls and removes the problem:
>
>--- modrdn.c.orig       Thu Jan  1 19:16:37 2004
>+++ modrdn.c    Tue Apr  6 12:43:21 2004
>@@ -613,21 +613,22 @@
>        case SLAPD_ABANDON:
>                goto return_results;
>        }
>-
>-       /* add new one */
>-       if ( dn2id_add( op->o_bd, &e->e_nname, e->e_id ) != 0 ) {
>-               send_ldap_error( op, rs, LDAP_OTHER,
>-                       "DN index add failed" );
>-               goto return_results;
>-       }
>+
>        /* delete old one */
>        if ( dn2id_delete( op->o_bd, &old_ndn, e->e_id ) != 0 ) {
>-               /* undo add of new one */
>-               dn2id_delete( op->o_bd, &e->e_nname, e->e_id );
>                send_ldap_error( op, rs, LDAP_OTHER,
>                        "DN index delete fail" );
>                goto return_results;
>        }
>+
>+       /* add new one */
>+       if ( dn2id_add( op->o_bd, &e->e_nname, e->e_id ) != 0 ) {
>+               /* add failed, try to repair old entry - probably hopeless */
>+               dn2id_add( op->o_bd, &old_ndn, e->e_id);
>+               send_ldap_error( op, rs, LDAP_OTHER,
>+                       "DN index add failed" );
>+               goto return_results;
>+       }
>
>        /* id2entry index */
>        if ( id2entry_add( op->o_bd, e ) != 0 ) {