[Samba] RPC: Problem Deleting LDAP-Entries in pdb_ldap.c

Yohann Fourteau yohann.fourteau at aitb.org
Wed Feb 25 16:37:58 GMT 2004


Well I found some problems with ldap_explode_dn which produce 
'\' + HEX strings and not UTF8.

Now the whole function deals with UTF8 strings, I've put the dn convertion at
the beginning.

I've removed the use of strndup. 

A strange thing is that sometime the dn is already in UTF8 and the
push_utf8_allocate() is just a strdup (when I change the name of a machine for
instance).


----------------------------------
--- a/smbldap.c	Thu Feb 19 15:52:00 2004
+++ b/smbldap.c	Wed Feb 25 17:28:43 2004
@@ -971,21 +971,284 @@
 	int 		attempts = 0;
 	char           *utf8_dn;
 
-	SMB_ASSERT(ldap_state);
+	BOOL		do_rename = False;
+	BOOL		naming_deleted = False;
+	BOOL		naming_more_value = False;
+	int		i,j,k;
+	char	       *rdn_attribut;
+	char	       *first_rdn;
+	char	       *new_rdn_value;
+	char	       *new_rdn;
+	char	       *rdn_value;
+	TALLOC_CTX     *t_ctx;
+	LDAPDN	       *parts;
+	LDAPDN	       *part;
+
+	/* 
+	 *  The naming attribute is the attribute used in the first RDN
+	 *  of the DN (first from the left). 
+	 *  Ex : uid=foo,ou=people,dc=boo,dc=com => Naming attribut is "uid"
+	 *
+	 *  In fact, it's a little bit more complex with multiple naming 
+	 *  attributes :
+	 *  Ex : uid=foo+cn=bar,ou=people,dc=boo,dc=com 
+	 *  (Not supported by that patch)
+	 * 
+	 *  The attrs array contains the list of the modification. 
+	 *  If the naming attribute is modified or deleted, the DN won't be
+	 *  correct.
+	 *
+	 *  To apply a modification on the naming attribute, you must modify 
+	 *  the DN with the ldap_modrdn2_s function. That function change the 
+	 *  naming attribute both in the DN and in the entry.
+	 * 
+	 *  The problem is that we must extract and remove the modification 
+	 *  of the naming attribute from the attrs array.
+	 *
+	 * */
+
+	t_ctx=talloc_init("smbldap_modify");
 
-	DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
 
 	if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
+		talloc_destroy(t_ctx);
+		return LDAP_NO_MEMORY;
+	}
+
+	/*  
+	 *  All strings are now in UTF8
+	 * */
+
+	/* 
+	 *  Extraction of the naming attribute from the DN
+	 *  rdn : array of rdn extrated from the DN
+	 *  rdn_attribut : naming attribute (string)
+	 *  utf8_rdn_value : value of the naming attribute 
+	 *  			in the DN (UTF8 string)
+	 *  
+	 * */
+	
+	/*
+	 *  ldap_explode_dn is deprecated in favor of 
+	 *  ldap_dn2str() and ldap_str_2dn.
+	 *
+	 *  The flag LDAP_DN_PRETTY causes UTF-8 to be represented.
+	 *  
+	 * */
+	
+	/* We build the first RDN in firstrdn */
+	ldap_str2dn(dn, &parts, LDAP_DN_FORMAT_LDAP);
+	
+	/*  We can use
+	 *  ldap_rdn2str(parts[0][0], &first_rdn,LDAP_DN_FORMAT_LDAPV3 |
LDAP_DN_PRETTY ); 
+	 *  or */
+	part=talloc(t_ctx,sizeof(char *) * 2);
+	if (!part) {
+		talloc_destroy(t_ctx);
+		SAFE_FREE(utf8_dn);
 		return LDAP_NO_MEMORY;
 	}
+	part[0]=talloc(t_ctx,sizeof(char *) * 2);
+	if (!part[0]) {
+		talloc_destroy(t_ctx);
+		SAFE_FREE(utf8_dn);
+		return LDAP_NO_MEMORY;
+	}
+	part[0][0]=parts[0][0];
+	part[0][1]=NULL;
+	part[1]=NULL;
+	ldap_dn2str(part, &first_rdn,LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
+	/* but ldap_rdn2str is not documented */
+
+	/* we take the rdn value */
+	rdn_value=talloc_strdup(t_ctx, strchr(first_rdn,'=')+1);
+	
+	if (!rdn_value) {
+		talloc_destroy(t_ctx);
+		SAFE_FREE(utf8_dn);
+		return LDAP_NO_MEMORY;
+	}
+	
+	
+	/*  we take the rdn attribute */
+	first_rdn[strlen(first_rdn)-strlen(rdn_value)-1]='\0';
+	rdn_attribut=talloc_strdup(t_ctx, first_rdn);
+	if (!rdn_attribut) {
+		SAFE_FREE(utf8_dn);
+		talloc_destroy(t_ctx);
+		return LDAP_NO_MEMORY;
+	}	
+	
+	/* we release the memory */
+	SAFE_FREE(first_rdn);
+	ldap_dnfree(parts);
+
+	DEBUG(5,("smbldap_modify: dn => [%s]\n", dn ));
+	
+	/* 
+	 *  We have to walk into the attrs array to find if the naming
+	 *  attributes is changed or deleted
+	 * 
+	 * */
+        for (i = 0; attrs[i] != NULL; i++) {
+		/*  
+		 *  If mod_type is the naming attribute
+		 *  Three cases : the operation is DELETE or ADD or REPLACE
+		 *  
+		 *  Note: Samba doesn't use REPLACE operation 
+		 *  for LDAP manipulation. Instead it uses two 
+		 *  operations : DELETE and ADD
+		 *  
+		 * */
+		if ( ( attrs[i]->mod_op == LDAP_MOD_DELETE )
+			&&  strequal(attrs[i]->mod_type,rdn_attribut) ) {
+			/*
+			 *  In the DELETE operation.
+			 *  If we have more than one value in the entry for 
+			 *  the naming attribute, the DELETE operation can
+			 *  delete other values than the one uses in the DN.
+			 *  
+			 *  So we have to walk into the mod_values arrray.
+			 *
+			 *  The values are in UTF8 (see smbldap_set_mod())
+			 *  So a simple strcmp is good.
+			 *  
+			 * */
+			for (j=0;attrs[i]->mod_values[j] != NULL; j++) {
+				if (!strcmp(attrs[i]->mod_values[j],
+							rdn_value)) {
+					/* The modification deletes 
+					 * the naming attribute. 
+					 * We have to remove that value 
+					 * from the mod_values array.
+					 * */
+					SAFE_FREE(attrs[i]->mod_values[j]);
+					attrs[i]->mod_values[j]=attrs[i]->mod_values[j+1];
+					for (k=j+1;attrs[i]->mod_values[k] != NULL; k++)
+						attrs[i]->mod_values[k]=attrs[i]->mod_values[k+1];
+					naming_deleted = True;
+				} else {
+					/* The modification deletes more than 
+					 * the naming attribute value */
+					naming_more_value = True;
+				}
+			}
+
+			/*  
+			 *  If we the DELETE operation delete only 
+			 *  the good value of the naming attribute, 
+			 *  we can remove that modification
+			 *  from the attrs array.
+			 *  
+			 * */
+			if (!naming_more_value) {
+				SAFE_FREE(attrs[i]->mod_type);
+				for (j=0;attrs[i]->mod_values[j] != NULL; j++)
+					SAFE_FREE(attrs[i]->mod_values[j]);
+				SAFE_FREE(attrs[i]->mod_values);
+				SAFE_FREE(attrs[i]); 
+				attrs[i]=attrs[i+1];
+				for (j=i+1; attrs[j] != NULL; j++) {
+					attrs[j]=attrs[j+1];
+				}
+			}
+		}
+
+		/*
+		 *  If we have removed the DELETE modification, we can be at the last item
from attrs
+		 *  array.
+		 *  
+		 * */
+		if ( ( attrs[i] != NULL ) 
+		      && ( ( attrs[i]->mod_op == LDAP_MOD_ADD 
+				      && naming_deleted ) 
+			      || attrs[i]->mod_op == LDAP_MOD_REPLACE )
+		      && ( attrs[i]->mod_values[0] != NULL)
+		      && ( strequal(attrs[i]->mod_type,rdn_attribut) ) ) {
+			/*
+			 *  In the ADD or REPLACE operation.
+			 *  If we add a naming attribute after 
+			 *  to have deleted it or if we replace 
+			 *  the naming attribute, we have to build 
+			 *  the new RDN of the entry.
+			 *
+			 *  We use the first value added to build the RDN.
+			 * */
+			do_rename = True;
+			new_rdn_value = talloc_strdup(t_ctx, 
+					attrs[i]->mod_values[0]);
+			if (!new_rdn_value) {
+				talloc_destroy(t_ctx);
+				SAFE_FREE(utf8_dn);
+				return LDAP_NO_MEMORY;
+			}
+			
+			/*  
+			 *  We build the new RDN in UTF8
+			 * */
+			new_rdn = talloc_asprintf(t_ctx,
+					"%s=%s",rdn_attribut,new_rdn_value);
+			if (!new_rdn) {
+				talloc_destroy(t_ctx);
+				SAFE_FREE(utf8_dn);
+				return LDAP_NO_MEMORY;
+			}
+			
+			DEBUG(5,("smbldap_modify: newdn => [%s]\n", new_rdn ));
+			/*  
+			 *  If it's an ADD operation, we have to remove 
+			 *  the first value from the operation 
+			 *  (or the complete operation if there is 
+			 *  only one value added).
+			 * */
+			if (attrs[i]->mod_op != LDAP_MOD_REPLACE) {
+				if (attrs[i]->mod_values[1] == NULL) {
+					SAFE_FREE(attrs[i]->mod_type);
+					for (j=0;attrs[i]->mod_values[j] != NULL; j++)
+						SAFE_FREE(attrs[i]->mod_values[j]);
+					SAFE_FREE(attrs[i]->mod_values);
+					SAFE_FREE(attrs[i]); 
+					attrs[i]=attrs[i+1];
+					for (j=i+1; attrs[j] != NULL; j++) {
+						attrs[j]=attrs[j+1];
+					}
+				} else {
+					SAFE_FREE(attrs[i]->mod_values[0]);
+					attrs[i]->mod_values[0]=attrs[i]->mod_values[1];
+					for (j=1;attrs[i]->mod_values[j] != NULL; j++)
+						attrs[i]->mod_values[j]=attrs[i]->mod_values[j+1];
+				}
+			}
+			/* We have our new RDN,
+			 * we can go out of the attrs array */
+			continue;
+		}
+	}
+
+	
+	SMB_ASSERT(ldap_state);
 
 	while ((rc == LDAP_SERVER_DOWN) && (attempts < SMBLDAP_NUM_RETRIES)) {
 		
 		if ((rc = smbldap_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
 			continue;
+
+		/*  
+		 *  We apply modifications on the entry.
+		 *
+		 * */
+		if ((rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs)) !=
LDAP_SUCCESS)
+			continue;
+		
+		/* 
+		 * We have detected a modification of the naming attribute 
+		 * and we have a new RDN.
+		 * */
+		if (do_rename)
+			rc = ldap_modrdn2_s(ldap_state->ldap_struct, utf8_dn, new_rdn, 1);
 		
-		rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
 	}
+
 	
 	if (rc == LDAP_SERVER_DOWN) {
 		DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
@@ -995,6 +1258,7 @@
 	ldap_state->last_use = time(NULL);
 
 	SAFE_FREE(utf8_dn);
+	talloc_destroy(t_ctx);
 	return rc;
 }
 
----------------------------------


-- 
Yohann F.


More information about the samba-technical mailing list