andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 4 months ago
Clone

Blame 0054-Ticket-47367-phase-1-ldapdelete-returns-non-leaf-ent.patch

dc8c34
From b6220eb610c92ead1a7e789317e158cfcb8def90 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@redhat.com>
dc8c34
Date: Thu, 6 Jun 2013 16:52:14 -0700
dc8c34
Subject: [PATCH 54/99] Ticket #47367 - (phase 1) ldapdelete returns non-leaf
dc8c34
 entry error while trying to remove a leaf entry
dc8c34
dc8c34
Bug description: Replication conflict confuses the numsubordinate
dc8c34
count, which leaves an entry that cannot be deleted even its
dc8c34
subordinate entries are all removed.
dc8c34
dc8c34
Fix description:
dc8c34
[urp.c] get_dn_plus_uniqueid: a logic to create a conflict DN
dc8c34
  had a bug.  It used to call slapi_sdn_get_rdn to get the rdn.
dc8c34
  The function slapi_sdn_get_rdn blindly returned the "dn" field
dc8c34
  without checking whether the field is NULL or not.  Instead,
dc8c34
  this patch changes the interface of the helper function get_
dc8c34
  dn_plus_uniqueid and use the original Slapi_DN with slapi_
dc8c34
  sdn_get_dn, then generates the conflict DN "nsuniqueid=...+
dc8c34
  <RDN>,<PARENT>".
dc8c34
[ldbm_delete.c] There is a case a parent of a delete-candidate
dc8c34
  entry runs into a conflict and multiple parent entries exist.
dc8c34
  Once it occurs, a parent entry found by the parent dn string
dc8c34
  may not be the entry which manages the numsubordinate count
dc8c34
  the delete-candidate entry belonging to.  It confuses the
dc8c34
  numsubordinate counts and leaves an entry which cannot be
dc8c34
  deleted due to the numsubordinate count mismatch. This patch
dc8c34
  retrieves parent entry by parent id if it is available.
dc8c34
[ldbm_entryrdn.c] When traversing the DIT, a special treatment
dc8c34
  is needed for a tombstone entry. I.e, 2 RDNs (nsuniqueid=...,
dc8c34
  <RDN>) is treated as one RDN.  It should decrement the index
dc8c34
  (rdnidx) one more to point to the right position of the RDN
dc8c34
  array in Slapi_RDN.
dc8c34
[ldbm_search.c] When checking the scope of an entry in ldbm_
dc8c34
  back_next_search_entry_ext, a tombstone entry was not properly
dc8c34
  examined.  This patch introduces a new slapi api slapi_sdn_
dc8c34
  scope_test_ext.
dc8c34
[dn.c] In slapi_sdn_get_rdn, use slapi_sdn_get_dn to get the
dc8c34
  dn value of Slapi_DN.  It was one cause of the problem in
dc8c34
  get_dn_plus_uniqueid (urp.c).
dc8c34
  This patch adds slapi_sdn_scope_test_ext, which takes flags
dc8c34
  to indicates the first argument dn is a tombstone sdn.
dc8c34
  Also, this patch replaces "malloc + strcpy + strcat" with
dc8c34
  slapi_ch_smprintf to improve the readability of the code.
dc8c34
[rdn.c] This patch replaces "malloc + strcpy + strcat" with
dc8c34
  slapi_create_dn_string to normalize the newly added rdn and
dc8c34
  improve the readability of the code.
dc8c34
dc8c34
Reviewed by Rich (Thank you!!)
dc8c34
dc8c34
https://fedorahosted.org/389/ticket/47367
dc8c34
(cherry picked from commit c2c64017e0e25a4376139debe29b4f587964710f)
dc8c34
---
dc8c34
 ldap/servers/plugins/replication/urp.c       | 18 ++++-----
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_delete.c   | 35 ++++++++++++-----
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c |  2 +
dc8c34
 ldap/servers/slapd/back-ldbm/ldbm_search.c   |  2 +-
dc8c34
 ldap/servers/slapd/dn.c                      | 59 +++++++++++++++++++++++++---
dc8c34
 ldap/servers/slapd/rdn.c                     | 24 ++++-------
dc8c34
 ldap/servers/slapd/slapi-plugin.h            | 18 +++++++++
dc8c34
 7 files changed, 116 insertions(+), 42 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
dc8c34
index 1d8799a..e236541 100644
dc8c34
--- a/ldap/servers/plugins/replication/urp.c
dc8c34
+++ b/ldap/servers/plugins/replication/urp.c
dc8c34
@@ -57,7 +57,7 @@ static int urp_annotate_dn (char *sessionid, Slapi_Entry *entry, CSN *opcsn, con
dc8c34
 static int urp_naming_conflict_removal (Slapi_PBlock *pb, char *sessionid, CSN *opcsn, const char *optype);
dc8c34
 static int mod_namingconflict_attr (const char *uniqueid, const Slapi_DN *entrysdn, const Slapi_DN *conflictsdn, CSN *opcsn);
dc8c34
 static int del_replconflict_attr (Slapi_Entry *entry, CSN *opcsn, int opflags);
dc8c34
-static char *get_dn_plus_uniqueid(char *sessionid,const char *olddn,const char *uniqueid);
dc8c34
+static char *get_dn_plus_uniqueid(char *sessionid,const Slapi_DN *oldsdn,const char *uniqueid);
dc8c34
 static char *get_rdn_plus_uniqueid(char *sessionid,const char *olddn,const char *uniqueid);
dc8c34
 static int is_suffix_entry (Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parenddn);
dc8c34
 
dc8c34
@@ -180,7 +180,7 @@ urp_add_operation( Slapi_PBlock *pb )
dc8c34
 	if (r<0)
dc8c34
 	{
dc8c34
 		/* Entry to be added is a loser */
dc8c34
-		char *newdn= get_dn_plus_uniqueid (sessionid, basedn, adduniqueid);
dc8c34
+		char *newdn = get_dn_plus_uniqueid (sessionid, (const Slapi_DN *)addentry, adduniqueid);
dc8c34
 		if(newdn==NULL)
dc8c34
 		{
dc8c34
 			op_result= LDAP_OPERATIONS_ERROR;
dc8c34
@@ -1222,16 +1222,15 @@ bailout:
dc8c34
 
dc8c34
 /* The returned value is either null or "uniqueid=<uniqueid>+<basedn>" */
dc8c34
 static char *
dc8c34
-get_dn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid)
dc8c34
+get_dn_plus_uniqueid(char *sessionid, const Slapi_DN *oldsdn, const char *uniqueid)
dc8c34
 {
dc8c34
-	Slapi_DN *sdn= slapi_sdn_new_dn_byval(olddn);
dc8c34
 	Slapi_RDN *rdn= slapi_rdn_new();
dc8c34
 	char *newdn;
dc8c34
 
dc8c34
 	PR_ASSERT(uniqueid!=NULL);
dc8c34
 
dc8c34
 	/* Check if the RDN already contains the Unique ID */
dc8c34
-	slapi_sdn_get_rdn(sdn,rdn);
dc8c34
+	slapi_rdn_set_dn(rdn, slapi_sdn_get_dn(oldsdn));
dc8c34
 	if(slapi_rdn_contains(rdn,SLAPI_ATTR_UNIQUEID,uniqueid,strlen(uniqueid)))
dc8c34
 	{
dc8c34
 		/* The Unique ID is already in the RDN.
dc8c34
@@ -1241,16 +1240,15 @@ get_dn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid)
dc8c34
 		 * require admin intercession
dc8c34
 		 */
dc8c34
 		slapi_log_error(SLAPI_LOG_FATAL, sessionid,
dc8c34
-				"Annotated DN %s has naming conflict\n", olddn );
dc8c34
+				"Annotated DN %s has naming conflict\n", slapi_sdn_get_dn(oldsdn) );
dc8c34
 		newdn= NULL;
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{
dc8c34
-		slapi_rdn_add(rdn,SLAPI_ATTR_UNIQUEID,uniqueid);
dc8c34
-		slapi_sdn_set_rdn(sdn, rdn);
dc8c34
-		newdn= slapi_ch_strdup(slapi_sdn_get_dn(sdn));
dc8c34
+		char *parentdn = slapi_dn_parent(slapi_sdn_get_dn(oldsdn));
dc8c34
+		slapi_rdn_add(rdn, SLAPI_ATTR_UNIQUEID, uniqueid);
dc8c34
+		newdn = slapi_ch_smprintf("%s,%s", slapi_rdn_get_rdn(rdn), parentdn);
dc8c34
 	}
dc8c34
-	slapi_sdn_free(&sdn;;
dc8c34
 	slapi_rdn_free(&rdn;;
dc8c34
 	return newdn;
dc8c34
 }
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
index 528693e..d80c54e 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
dc8c34
@@ -242,14 +242,12 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 	 */
dc8c34
 	is_tombstone_entry = slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
dc8c34
 	if (delete_tombstone_entry) {
dc8c34
-		PR_ASSERT(is_tombstone_entry);
dc8c34
 		if (!is_tombstone_entry) {
dc8c34
 			slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
dc8c34
 					"Attempt to delete a non-tombstone entry %s\n", dn);
dc8c34
 			delete_tombstone_entry = 0;
dc8c34
 		}
dc8c34
 	} else {
dc8c34
-		PR_ASSERT(!is_tombstone_entry);
dc8c34
 		if (is_tombstone_entry) { 
dc8c34
 				slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
dc8c34
 					"Attempt to Tombstone again a tombstone entry %s\n", dn);
dc8c34
@@ -328,12 +326,31 @@ ldbm_back_delete( Slapi_PBlock *pb )
dc8c34
 	if ( !slapi_sdn_isempty(&parentsdn) )
dc8c34
 	{
dc8c34
 		struct backentry *parent = NULL;
dc8c34
-		entry_address parent_addr;
dc8c34
+		char *pid_str = slapi_entry_attr_get_charptr(e->ep_entry, LDBM_PARENTID_STR);
dc8c34
+		if (pid_str) {
dc8c34
+			/* First, try to get the direct parent. */
dc8c34
+			/* 
dc8c34
+			 * Although a rare case, multiple parents from repl conflict could exist.
dc8c34
+			 * In such case, if a parent entry is found just by parentsdn
dc8c34
+			 * (find_entry2modify_only_ext), a wrong parent could be found,
dc8c34
+			 * and numsubordinate count could get confused.
dc8c34
+			 */
dc8c34
+			ID pid = (ID)strtol(pid_str, (char **)NULL, 10);
dc8c34
+			parent = id2entry(be, pid ,NULL, &retval);
dc8c34
+			if (parent && cache_lock_entry(&inst->inst_cache, parent)) {
dc8c34
+				/* Failed to obtain parent entry's entry lock */
dc8c34
+				CACHE_RETURN(&(inst->inst_cache), &parent);
dc8c34
+				goto error_return;
dc8c34
+			}
dc8c34
+		}
dc8c34
+		if (NULL == parent) {
dc8c34
+			entry_address parent_addr;
dc8c34
 
dc8c34
-		parent_addr.sdn = &parentsdn;
dc8c34
-		parent_addr.uniqueid = NULL;
dc8c34
-		parent = find_entry2modify_only_ext(pb, be, &parent_addr,
dc8c34
-		                                    TOMBSTONE_INCLUDED, &txn);
dc8c34
+			parent_addr.sdn = &parentsdn;
dc8c34
+			parent_addr.uniqueid = NULL;
dc8c34
+			parent = find_entry2modify_only_ext(pb, be, &parent_addr,
dc8c34
+		                                        TOMBSTONE_INCLUDED, &txn);
dc8c34
+		}
dc8c34
 		if (NULL != parent) {
dc8c34
 			int isglue;
dc8c34
 			size_t haschildren = 0;
dc8c34
@@ -1171,9 +1188,9 @@ common_return:
dc8c34
 	}
dc8c34
 
dc8c34
 diskfull_return:
dc8c34
-    if(ldap_result_code!=-1)
dc8c34
+	if(ldap_result_code!=-1)
dc8c34
 	{
dc8c34
-    	slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
dc8c34
+		slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
dc8c34
 	}
dc8c34
 	modify_term(&parent_modify_c,be);
dc8c34
 	if(dblock_acquired)
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
dc8c34
index e50b930..4329b16 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
dc8c34
@@ -3164,6 +3164,7 @@ _entryrdn_index_read(backend *be,
dc8c34
             /* Node might be a tombstone. */
dc8c34
             rc = _entryrdn_get_tombstone_elem(cursor, tmpsrdn, 
dc8c34
                                               &key, nrdn, elem);
dc8c34
+            rdnidx--; /* consider nsuniqueid=..,<RDN> one RDN */
dc8c34
         }
dc8c34
         if (rc || NULL == *elem) {
dc8c34
             slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
dc8c34
@@ -3270,6 +3271,7 @@ _entryrdn_index_read(backend *be,
dc8c34
                     }
dc8c34
                     goto bail;
dc8c34
                 }
dc8c34
+                rdnidx--; /* consider nsuniqueid=..,<RDN> one RDN */
dc8c34
             } else {
dc8c34
                 slapi_ch_free((void **)&tmpelem);
dc8c34
                 if (DB_NOTFOUND != rc) {
dc8c34
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
index 5fbea24..f86f27c 100644
dc8c34
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
dc8c34
@@ -1610,7 +1610,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
dc8c34
              * just forget about it, since we don't want to return anything at all. */
dc8c34
          {
dc8c34
              if ( slapi_uniqueIDCompareString(target_uniqueid, e->ep_entry->e_uniqueid) ||
dc8c34
-                  slapi_sdn_scope_test( backentry_get_sdn(e), basesdn, scope ))
dc8c34
+                  slapi_sdn_scope_test_ext( backentry_get_sdn(e), basesdn, scope, e->ep_entry->e_flags ))
dc8c34
              {
dc8c34
                  /* check size limit */
dc8c34
                  if ( slimit >= 0 )
dc8c34
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
dc8c34
index 35c0700..2f50e97 100644
dc8c34
--- a/ldap/servers/slapd/dn.c
dc8c34
+++ b/ldap/servers/slapd/dn.c
dc8c34
@@ -2114,10 +2114,7 @@ slapi_sdn_add_rdn(Slapi_DN *sdn, const Slapi_RDN *rdn)
dc8c34
 	{
dc8c34
 		/* NewDN= NewRDN + DN */
dc8c34
 		const char *dn= slapi_sdn_get_dn(sdn);
dc8c34
-		char *newdn= slapi_ch_malloc(strlen(rawrdn)+1+strlen(dn)+1);
dc8c34
-		strcpy( newdn, rawrdn );
dc8c34
-		strcat( newdn, "," );
dc8c34
-		strcat( newdn, dn );
dc8c34
+		char *newdn = slapi_ch_smprintf("%s,%s", rawrdn, dn);
dc8c34
 		slapi_sdn_set_dn_passin(sdn,newdn);
dc8c34
 	}
dc8c34
 	return sdn;
dc8c34
@@ -2345,7 +2342,7 @@ slapi_sdn_get_backend_parent(const Slapi_DN *sdn,Slapi_DN *sdn_parent,const Slap
dc8c34
 void
dc8c34
 slapi_sdn_get_rdn(const Slapi_DN *sdn,Slapi_RDN *rdn)
dc8c34
 {
dc8c34
-	slapi_rdn_set_dn(rdn,sdn->dn);
dc8c34
+	slapi_rdn_set_dn(rdn, slapi_sdn_get_dn(sdn));
dc8c34
 }
dc8c34
 
dc8c34
 Slapi_DN *
dc8c34
@@ -2516,6 +2513,47 @@ slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope )
dc8c34
     return rc;
dc8c34
 }
dc8c34
 
dc8c34
+/* 
dc8c34
+ * Return non-zero if "dn" matches the scoping criteria
dc8c34
+ * given by "base" and "scope".
dc8c34
+ * If SLAPI_ENTRY_FLAG_TOMBSTONE is set to flags,
dc8c34
+ * DN without "nsuniqueid=...," is examined.
dc8c34
+ */
dc8c34
+int
dc8c34
+slapi_sdn_scope_test_ext( const Slapi_DN *dn, const Slapi_DN *base, int scope, int flags )
dc8c34
+{
dc8c34
+    int rc = 0;
dc8c34
+
dc8c34
+    switch ( scope ) {
dc8c34
+    case LDAP_SCOPE_BASE:
dc8c34
+        if (flags & SLAPI_ENTRY_FLAG_TOMBSTONE) {
dc8c34
+            Slapi_DN parent;
dc8c34
+            slapi_sdn_init(&parent);
dc8c34
+            slapi_sdn_get_parent(dn, &parent);
dc8c34
+            rc = ( slapi_sdn_compare( dn, &parent ) == 0 );
dc8c34
+            slapi_sdn_done(&parent);
dc8c34
+        } else {
dc8c34
+            rc = ( slapi_sdn_compare( dn, base ) == 0 );
dc8c34
+        }
dc8c34
+        break;
dc8c34
+    case LDAP_SCOPE_ONELEVEL:
dc8c34
+        if (flags & SLAPI_ENTRY_FLAG_TOMBSTONE) {
dc8c34
+            Slapi_DN parent;
dc8c34
+            slapi_sdn_init(&parent);
dc8c34
+            slapi_sdn_get_parent(dn, &parent);
dc8c34
+            rc = ( slapi_sdn_isparent( base, &parent ) != 0 );
dc8c34
+            slapi_sdn_done(&parent);
dc8c34
+        } else {
dc8c34
+            rc = ( slapi_sdn_isparent( base, dn ) != 0 );
dc8c34
+        }
dc8c34
+        break;
dc8c34
+    case LDAP_SCOPE_SUBTREE:
dc8c34
+        rc = ( slapi_sdn_issuffix( dn, base ) != 0 );
dc8c34
+        break;
dc8c34
+    }
dc8c34
+    return rc;
dc8c34
+}
dc8c34
+
dc8c34
 /*
dc8c34
  * build the new dn of an entry for moddn operations
dc8c34
  */
dc8c34
@@ -2563,7 +2601,16 @@ size_t
dc8c34
 slapi_sdn_get_size(const Slapi_DN *sdn)
dc8c34
 {
dc8c34
     size_t sz = sizeof(Slapi_DN);
dc8c34
+    /* slapi_sdn_get_ndn_len returns the normalized dn length
dc8c34
+     * if dn or ndn exists.  If both does not exist, it
dc8c34
+     * normalizes udn and set it to dn and returns the length.
dc8c34
+     */
dc8c34
     sz += slapi_sdn_get_ndn_len(sdn);
dc8c34
-    sz += strlen(sdn->dn) + 1;
dc8c34
+    if (sdn->dn && sdn->ndn) {
dc8c34
+        sz += slapi_sdn_get_ndn_len(sdn);
dc8c34
+    }
dc8c34
+    if (sdn->udn) {
dc8c34
+        sz += strlen(sdn->udn) + 1;
dc8c34
+    }
dc8c34
     return sz;
dc8c34
 }
dc8c34
diff --git a/ldap/servers/slapd/rdn.c b/ldap/servers/slapd/rdn.c
dc8c34
index d408f0e..fe2fae0 100644
dc8c34
--- a/ldap/servers/slapd/rdn.c
dc8c34
+++ b/ldap/servers/slapd/rdn.c
dc8c34
@@ -479,25 +479,17 @@ slapi_rdn_add(Slapi_RDN *rdn, const char *type, const char *value)
dc8c34
 	PR_ASSERT(NULL != value);
dc8c34
 	if(rdn->rdn==NULL)
dc8c34
 	{
dc8c34
-	    /* type=value '\0' */
dc8c34
-		rdn->rdn= slapi_ch_malloc(strlen(type)+1+strlen(value)+1);
dc8c34
-		strcpy( rdn->rdn, type );
dc8c34
-		strcat( rdn->rdn, "=" );
dc8c34
-		strcat( rdn->rdn, value );
dc8c34
+		/* type=value '\0' */
dc8c34
+		rdn->rdn = slapi_create_dn_string("%s=%s", type, value);
dc8c34
 	}
dc8c34
 	else
dc8c34
 	{
dc8c34
-	    /* type=value+rdn '\0' */
dc8c34
-		char *newrdn= slapi_ch_malloc(strlen(type)+1+strlen(value)+1+strlen(rdn->rdn)+1);
dc8c34
-		strcpy( newrdn, type );
dc8c34
-		strcat( newrdn, "=" );
dc8c34
-		strcat( newrdn, value );
dc8c34
-		strcat( newrdn, "+" );
dc8c34
-		strcat( newrdn, rdn->rdn );
dc8c34
-		slapi_ch_free((void**)&rdn->rdn);
dc8c34
-		rdn->rdn= newrdn;
dc8c34
-	}
dc8c34
-    slapi_unsetbit_uchar(rdn->flag,FLAG_RDNS);
dc8c34
+		/* type=value+rdn '\0' */
dc8c34
+		char *newrdn = slapi_create_dn_string("%s=%s+%s", type, value, rdn->rdn);
dc8c34
+		slapi_ch_free_string(&rdn->rdn);
dc8c34
+		rdn->rdn = newrdn;
dc8c34
+	}
dc8c34
+	slapi_unsetbit_uchar(rdn->flag,FLAG_RDNS);
dc8c34
 	return 1;
dc8c34
 }
dc8c34
 
dc8c34
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
dc8c34
index f78787e..0f69c0a 100644
dc8c34
--- a/ldap/servers/slapd/slapi-plugin.h
dc8c34
+++ b/ldap/servers/slapd/slapi-plugin.h
dc8c34
@@ -2698,6 +2698,24 @@ int slapi_sdn_get_ndn_len(const Slapi_DN *sdn);
dc8c34
 int slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope );
dc8c34
 
dc8c34
 /**
dc8c34
+ * Checks if a DN is within a specified scope under a specified base DN.
dc8c34
+ * This api adjusts tombstoned DN when comparing with the base dn.
dc8c34
+ *
dc8c34
+ * \param dn A pointer to the \c Slapi_DN structure to test.
dc8c34
+ * \param base The base DN against which \c dn is going to be tested.
dc8c34
+ * \param scope The scope tested.  Valid scopes are:
dc8c34
+ *        \arg \c LDAP_SCOPE_BASE
dc8c34
+ *        \arg \c LDAP_SCOPE_ONELEVEL
dc8c34
+ *        \arg \c LDAP_SCOPE_SUBTREE
dc8c34
+ * \param flags 0 or SLAPI_ENTRY_FLAG_TOMBSTONE
dc8c34
+ * \return non-zero if \c dn matches the scoping criteria given by \c base and \c scope.
dc8c34
+ * \see slapi_sdn_compare()
dc8c34
+ * \see slapi_sdn_isparent()
dc8c34
+ * \see slapi_sdn_issuffix()
dc8c34
+ */
dc8c34
+int slapi_sdn_scope_test_ext( const Slapi_DN *dn, const Slapi_DN *base, int scope, int flags );
dc8c34
+
dc8c34
+/**
dc8c34
  * Retreives the RDN from a given DN.
dc8c34
  *
dc8c34
  * This function takes the DN stored in the \c Slapi_DN structure pointed to
dc8c34
-- 
dc8c34
1.8.1.4
dc8c34