From 9a5ea28d9bdaa5334346ab3e651c48f3d7a12523 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Tue, 12 Feb 2008 01:32:01 +0000
Subject: [PATCH] ITS#5293

---
 CHANGES                    |   1 +
 clients/tools/ldapdelete.c | 141 ++++++++++++++-----------------------
 2 files changed, 53 insertions(+), 89 deletions(-)

diff --git a/CHANGES b/CHANGES
index dc4027a8f8..733b0bc57b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,7 @@ OpenLDAP 2.4.8 Engineering
 	Fixed libldap paged results crash (ITS#5315)
 	Fixed libldap use of %n (ITS#5324)
 	Fixed ldapdelete with sizelimit (ITS#5294)
+	Fixed ldapdelete with subentries control (ITS#5293)
 	Fixed slapd support for 2.1 CSN (ITS#5348)
 	Fixed slapd idlcache on adds (ITS#5086)
 	Fixed slapd include handling (ITS#5276)
diff --git a/clients/tools/ldapdelete.c b/clients/tools/ldapdelete.c
index 327cd1fa52..754d96aae4 100644
--- a/clients/tools/ldapdelete.c
+++ b/clients/tools/ldapdelete.c
@@ -60,7 +60,8 @@ static int dodelete LDAP_P((
 
 static int deletechildren LDAP_P((
 	LDAP *ld,
-	const char *dn ));
+	const char *dn,
+	int subentries ));
 
 void
 usage( void )
@@ -238,6 +239,7 @@ static int dodelete(
 	char *matcheddn = NULL, *text = NULL, **refs = NULL;
 	LDAPControl **ctrls = NULL;
 	LDAPMessage *res;
+	int subentries = 0;
 
 	if ( verbose ) {
 		printf( _("%sdeleting entry \"%s\"\n"),
@@ -251,7 +253,10 @@ static int dodelete(
 	/* If prune is on, remove a whole subtree.  Delete the children of the
 	 * DN recursively, then the DN requested.
 	 */
-	if ( prune ) deletechildren( ld, dn );
+	if ( prune ) {
+retry:;
+		deletechildren( ld, dn, subentries );
+	}
 
 	rc = ldap_delete_ext( ld, dn, NULL, NULL, &id );
 	if ( rc != LDAP_SUCCESS ) {
@@ -283,7 +288,18 @@ static int dodelete(
 
 	rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 );
 
-	if( rc != LDAP_SUCCESS ) {
+	switch ( rc ) {
+	case LDAP_SUCCESS:
+		break;
+
+	case LDAP_NOT_ALLOWED_ON_NONLEAF:
+		if ( prune && !subentries ) {
+			subentries = 1;
+			goto retry;
+		}
+		/* fallthru */
+
+	default:
 		fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n",
 			prog, ldap_err2string( rc ), rc );
 		return rc;
@@ -316,7 +332,7 @@ static int dodelete(
 	if (ctrls) {
 		tool_print_ctrls( ld, ctrls );
 		ldap_controls_free( ctrls );
-    }
+	}
 
 	ber_memfree( text );
 	ber_memfree( matcheddn );
@@ -330,24 +346,48 @@ static int dodelete(
  */
 static int deletechildren(
 	LDAP *ld,
-	const char *base )
+	const char *base,
+	int subentries )
 {
 	LDAPMessage *res, *e;
 	int entries;
-	int rc, srch_rc;
+	int rc = LDAP_SUCCESS, srch_rc;
 	static char *attrs[] = { LDAP_NO_ATTRS, NULL };
-	LDAPControl c, *ctrls[2];
+	LDAPControl c, *ctrls[2], **ctrlsp = NULL;
 	BerElement *ber = NULL;
-	LDAPMessage *res_se;
 
 	if ( verbose ) printf ( _("deleting children of: %s\n"), base );
 
+	if ( subentries ) {
+		/*
+		 * Do a one level search at base for subentry children.
+		 */
+
+		if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
+			return EXIT_FAILURE;
+		}
+		rc = ber_printf( ber, "b", 1 );
+		if ( rc == -1 ) {
+			ber_free( ber, 1 );
+			fprintf( stderr, _("Subentries control encoding error!\n"));
+			return EXIT_FAILURE;
+		}
+		if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
+			return EXIT_FAILURE;
+		}
+		c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
+		c.ldctl_iscritical = 1;
+		ctrls[0] = &c;
+		ctrls[1] = NULL;
+		ctrlsp = ctrls;
+	}
+
 	/*
 	 * Do a one level search at base for children.  For each, delete its children.
 	 */
 more:;
 	srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
-		NULL, NULL, NULL, sizelimit, &res );
+		ctrlsp, NULL, NULL, sizelimit, &res );
 	switch ( srch_rc ) {
 	case LDAP_SUCCESS:
 	case LDAP_SIZELIMIT_EXCEEDED:
@@ -374,8 +414,8 @@ more:;
 				return rc;
 			}
 
-			rc = deletechildren( ld, dn );
-			if ( rc == -1 ) {
+			rc = deletechildren( ld, dn, 0 );
+			if ( rc != LDAP_SUCCESS ) {
 				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
 				ber_memfree( dn );
 				return rc;
@@ -386,7 +426,7 @@ more:;
 			}
 
 			rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
-			if ( rc == -1 ) {
+			if ( rc != LDAP_SUCCESS ) {
 				tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
 				ber_memfree( dn );
 				return rc;
@@ -407,82 +447,5 @@ more:;
 		goto more;
 	}
 
-	/*
-	 * Do a one level search at base for subentry children.
-	 */
-
-	if ((ber = ber_alloc_t(LBER_USE_DER)) == NULL) {
-		return EXIT_FAILURE;
-	}
-	rc = ber_printf( ber, "b", 1 );
-	if ( rc == -1 ) {
-		ber_free( ber, 1 );
-		fprintf( stderr, _("Subentries control encoding error!\n"));
-		return EXIT_FAILURE;
-	}
-	if ( ber_flatten2( ber, &c.ldctl_value, 0 ) == -1 ) {
-		return EXIT_FAILURE;
-	}
-	c.ldctl_oid = LDAP_CONTROL_SUBENTRIES;
-	c.ldctl_iscritical = 1;
-	ctrls[0] = &c;
-	ctrls[1] = NULL;
-
-more2:;
-	srch_rc = ldap_search_ext_s( ld, base, LDAP_SCOPE_ONELEVEL, NULL, attrs, 1,
-		ctrls, NULL, NULL, sizelimit, &res_se );
-	switch ( srch_rc ) {
-	case LDAP_SUCCESS:
-	case LDAP_SIZELIMIT_EXCEEDED:
-		break;
-	default:
-		tool_perror( "ldap_search", srch_rc, NULL, NULL, NULL, NULL );
-		return( srch_rc );
-	}
-	ber_free( ber, 1 );
-
-	entries = ldap_count_entries( ld, res_se );
-
-	if ( entries > 0 ) {
-		int i;
-
-		for (e = ldap_first_entry( ld, res_se ), i = 0; e != NULL;
-			e = ldap_next_entry( ld, e ), i++ )
-		{
-			char *dn = ldap_get_dn( ld, e );
-
-			if( dn == NULL ) {
-				ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &rc );
-				tool_perror( "ldap_prune", rc, NULL, NULL, NULL, NULL );
-				ber_memfree( dn );
-				return rc;
-			}
-
-			if ( verbose ) {
-				printf( _("\tremoving %s\n"), dn );
-			}
-
-			rc = ldap_delete_ext_s( ld, dn, NULL, NULL );
-			if ( rc == -1 ) {
-				tool_perror( "ldap_delete", rc, NULL, NULL, NULL, NULL );
-				ber_memfree( dn );
-				return rc;
-
-			}
-			
-			if ( verbose ) {
-				printf( _("\t%s removed\n"), dn );
-			}
-
-			ber_memfree( dn );
-		}
-	}
-
-	ldap_msgfree( res_se );
-
-	if ( srch_rc == LDAP_SIZELIMIT_EXCEEDED ) {
-		goto more2;
-	}
-
 	return rc;
 }
-- 
GitLab