When a new mapping tree node is added over the wire, the callback mapping_tree_entry_add() handles it. This function looks through the entry and handles the various important attributes. In particular, it finds the nsslapd-parent-suffix attribute to see if we're adding a child-node (sub-suffix). We use get_parent_from_entry() to get the value, e.g. ""dc=example,dc=com"" (literal quotes). get_parent_from_entry() strips off quotes if they are present before searching for existing in-memory parent node. This means that a child node like this: dn: cn="ou=test,dc=example,dc=com",cn=mapping tree,cn=config objectClass: top objectClass: nsMappingTree objectClass: extensibleObject nsslapd-state: backend nsslapd-backend: testRoot nsslapd-parent-suffix: dc=example,dc=com cn: "ou=test,dc=example,dc=com" Would be considered a valid child-node of: dn: cn="dc=example,dc=com",cn=mapping tree,cn=config objectClass: top objectClass: nsMappingTree objectClass: extensibleObject nsslapd-state: backend nsslapd-backend: userRoot cn: "dc=example,dc=com" Normally it wouldn't, since "dc=example,dc=com" is not equivalent to ""dc=example,dc=com"" (literal quotes). This allows a sub-suffix to be added over the wire with the parent suffix specified with or without quotes. The problem comes after a restart. When the mapping tree is initialized from dse.ldif, the quotes ARE significant because the function mapping_tree_node_get_children() performs searches like "(&(objectclass=nsMappingTree)(%s=\"%s\"))". Note the literal quotes in the search filter. This means the sub-suffix will not be usable after a restart because it will not be found by the search.
I've noticed this too, recently. We used to have this: cn: "dc=example,dc=com" cn: dc=example,dc=com But now it's only the one with the quotes.
It was introduced by this change I made to fix bz#438139: https://bugzilla.redhat.com/attachment.cgi?id=328240&action=diff#util.c_sec1/ I accidentally removed this case for '"'. :( Index: util.c =================================================================== RCS file: /cvs/dirsec/ldapserver/ldap/servers/slapd/util.c,v retrieving revision 1.28 diff -t -w -U 8 -r1.28 util.c --- util.c 4 Feb 2009 18:21:01 -0000 1.28 +++ util.c 5 Mar 2009 22:43:22 -0000 @@ -208,16 +208,18 @@ strcpy_unescape_value( char *d, const char *s ) { int gotesc = 0; const char *end = s + strlen(s); for ( ; *s; s++ ) { switch ( *s ) { + case '"': + break; case '\\': if ( gotesc ) { gotesc = 0; } else { By recovering this code, I could resume both cn values: dn: cn="dc=test,dc=com",cn=mapping tree, cn=config objectClass: top objectClass: extensibleObject objectClass: nsMappingTree nsslapd-state: Backend cn: "dc=test,dc=com" cn: dc=test,dc=com nsslapd-backend: testRoot dn: cn="dc=test,dc=example,dc=com",cn=mapping tree, cn=config objectClass: top objectClass: extensibleObject objectClass: nsMappingTree nsslapd-state: Backend cn: "dc=test,dc=example,dc=com" cn: dc=test,dc=example,dc=com nsslapd-parent-suffix: "dc=example,dc=com" nsslapd-backend: subtestRoot B*U*T, except "dc=example,dc=com": the first suffix created at the instance creation... dn: cn="dc=example,dc=com",cn=mapping tree,cn=config objectClass: top objectClass: extensibleObject objectClass: nsMappingTree cn: "dc=example,dc=com" nsslapd-state: backend nsslapd-backend: userRoot I'm puzzled why this difference is made...
Needing both a quoted and an unquoted value shouldn't really be needed I think. My concern was that mixing the use of quotes works fine when setting up the mapping tree over LDAP, but when the mapping tree is initialized from dse.ldif it does not work. Unfortunately the documentation uses mixed quoting which led to some confusing situations where the sub-suffix configuration worked until the instance was restarted. I filed a separate documentation bug for that: 488818 This bug is low priority in my opinion as long as the documentation is correct. A quick fix to this bug to make the behavior between adding over LDAP and reading from dse.ldif might be to change the search filter in mapping_tree_node_get_children() to something like this: "(&(objectclass=nsMappingTree)(|(%s=\"%s\")(%s=%s)))"
I also think that's a good idea. Something like this, right? Index: mapping_tree.c =================================================================== RCS file: /cvs/dirsec/ldapserver/ldap/servers/slapd/mapping_tree.c,v retrieving revision 1.17 diff -t -w -U 8 -r1.17 mapping_tree.c --- mapping_tree.c 4 Dec 2008 00:42:18 -0000 1.17 +++ mapping_tree.c 6 Mar 2009 00:06:34 -0000 @@ -905,17 +905,17 @@ /* Remember that the root node of the mapping tree is the NULL suffix. * Since we don't really support it, children of the root node won't * have a MAPPING_TREE_PARENT_ATTRIBUTE. */ if (is_root) { filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(!(%s=*)))", MAPPING_TREE_PARENT_ATTRIBUTE); } else { - filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(%s=\"%s\"))", + filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(|(%s=\"%s\")(%s=%s)))", MAPPING_TREE_PARENT_ATTRIBUTE, slapi_sdn_get_dn(target->mtn_subtree)); }
yes, except the latter diff should be like this: + filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(|(%s=\"%s\")(%s=%s)))", MAPPING_TREE_PARENT_ATTRIBUTE, slapi_sdn_get_dn(target->mtn_subtree), MAPPING_TREE_PARENT_ATTRIBUTE, slapi_sdn_get_dn(target->mtn_subtree));
I tested the change in the comment #5 Rich put. It passed the mapping tree test 100%. mappingTree run 100% (7/7) Index: mapping_tree.c =================================================================== RCS file: /cvs/dirsec/ldapserver/ldap/servers/slapd/mapping_tree.c,v retrieving revision 1.17 diff -t -w -U 8 -r1.17 mapping_tree.c --- mapping_tree.c 4 Dec 2008 00:42:18 -0000 1.17 +++ mapping_tree.c 7 Mar 2009 00:41:44 -0000 @@ -905,17 +905,19 @@ /* Remember that the root node of the mapping tree is the NULL suffix. * Since we don't really support it, children of the root node won't * have a MAPPING_TREE_PARENT_ATTRIBUTE. */ if (is_root) { filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(!(%s=*)))", MAPPING_TREE_PARENT_ATTRIBUTE); } else { - filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(%s=\"%s\"))", + filter = slapi_ch_smprintf("(&(objectclass=nsMappingTree)(|(%s=\"%s\")(%s=%s)))", + MAPPING_TREE_PARENT_ATTRIBUTE, + slapi_sdn_get_dn(target->mtn_subtree), MAPPING_TREE_PARENT_ATTRIBUTE, slapi_sdn_get_dn(target->mtn_subtree)); } slapi_search_internal_set_pb(pb, MAPPING_TREE_BASE_DN, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, NULL, NULL, (void *) plugin_get_default_component_id(), 0); slapi_search_internal_pb(pb); slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res); I've marked reviewed. Rich, could you check in the code? Thanks! --noriko
Checking in mapping_tree.c; /cvs/dirsec/ldapserver/ldap/servers/slapd/mapping_tree.c,v <-- mapping_tree.c new revision: 1.18; previous revision: 1.17 done
I am able to create cn="dc=example,dc=com" and cn=dc=example,dc=com and I can add sub domains to both without errors upon restart Verified against 8.1.0-2
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on therefore solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHEA-2009-0455.html