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

Slapd blows away rdn



slapd allows an entry's rdn to be replaced.  If a
ldapmodify user issues a replace operation for the rdn 
attribute,  slapd will blow away all the corresponding
attributes,  and remove the rdn from the associated indexes.
This makes the entry hard to find.

We have modified servers/slapd/back-ldbm/modify.c to correct this
problem.  We have yet to put this change into production,  but are
planning to real soon.


Here are the diffs.


Index: modify.c
===================================================================
RCS file: /repo/OpenLDAP/pkg/ldap/servers/slapd/back-ldbm/modify.c,v
retrieving revision 1.4.2.3.2.10
diff -r1.4.2.3.2.10 modify.c
33c33
< 	int		i, err;
- ---
> 	int		i, k, err;
113c113,114
< 	/* remove old indices */
- ---
> 	/* remove old indices                    */
> 	/* But don't remove any attrs in the rdn */
114a116,139
>     	char        *rdn, *rdn_type, *rdn_value;
>     	struct berval   val;
> 
> 		rdn = dn_rdn (NULL, e->e_dn);
> 		rdn_type = rdn_attr_type( rdn );
>    		if (rdn_type == NULL ) {
> 			Debug( LDAP_DEBUG_ANY, "Bad RDN type for entry (%s)\n",
>            								e->e_dn, 0, 0 );
> 			free (rdn);
> 			return( -1 );
> 		}
> 		rdn_value = rdn_attr_value ( rdn );
>    		if (rdn_value == NULL ) {
> 			Debug( LDAP_DEBUG_ANY, "Bad RDN value for entry (%s)\n",
>            								e->e_dn, 0, 0 );
> 			free (rdn);
> 			free (rdn_type);
> 			return( -1 );
> 		}
> 
> 	   	val.bv_len = strlen( rdn_value );
> 		val.bv_val = rdn_value;
> 		value_normalize( val.bv_val, attr_syntax( rdn_type ));
> 
122a148,170
> 
> 					if (! strcasecmp (mod->mod_type, rdn_type) ) {
> 
> 						i = 0;
> 						while ( a->a_vals[ i ] != NULL ) {
> 
> 
> 							if ( value_cmp 
> 				(&val, a->a_vals[ i ], attr_syntax( rdn_type ), 2 ) == 0 ) {
>    
> 								/* found a non matching value - delete it */
> 								ber_bvfree( a->a_vals[i] );
> 								for ( k = i + 1; a->a_vals[k] != NULL; k++ ) {
> 									a->a_vals[k - 1] = a->a_vals[k];
> 								}
> 								a->a_vals[k - 1] = NULL;
> 							
> 								continue;
> 							}
> 							i++;
> 						}
> 					}
> 
131a180,182
> 		free (rdn_type);
> 		free (rdn_value);
> 		free (rdn);
239a291,293
> 	char		*rdn, *rdn_type, *rdn_value;
> 	struct berval	rdn_berval;
> 	int			deleted;
241,249c295
< 	/* delete the entire attribute */
< 	if ( mod->mod_bvalues == NULL ) {
< 		Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
< 		    mod->mod_type, 0, 0 );
< 		return( attr_delete( &e->e_attrs, mod->mod_type ) ?
< 		    LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
< 	}
< 
< 	/* delete specific values - find the attribute first */
- ---
> 	/* find the attribute first */
255a302,386
> 	/* Determine the RDN -- we won't delete the RDN */
> 	rdn = dn_rdn (NULL, e->e_dn);
> 	rdn_type = rdn_attr_type( rdn );
> 	if (rdn_type == NULL ) {
> 		Debug( LDAP_DEBUG_ANY, "Bad RDN type for entry (%s)\n",
> 			e->e_dn, 0, 0 );
> 		free (rdn);
> 		return( LDAP_INVALID_DN_SYNTAX );
> 	}
> 
> 	/* Don't delete the attribute that matches the rdn! */
> 	if (strcasecmp (rdn_type, mod->mod_type) == 0){
> 	
> 		rdn_value = rdn_attr_value ( rdn );	
> 		if (rdn_value == NULL ) {
> 			Debug( LDAP_DEBUG_ANY, "Bad RDN value for entry (%s)\n",
> 						e->e_dn, 0, 0 );
> 			free (rdn);
> 			free (rdn_type);
> 			return( LDAP_INVALID_DN_SYNTAX );
> 		}
> 		rdn_berval.bv_len = strlen( rdn_value );
> 		rdn_berval.bv_val = rdn_value;
> 		value_normalize( rdn_berval.bv_val, attr_syntax( rdn_type ));
> 
> 		j = 0;
> 		while (a->a_vals[j] != NULL ) {
> 			deleted = 0;
> 
> 			if ( value_cmp (&rdn_berval, a->a_vals[ j ], attr_syntax( rdn_type ), 2 )== 0 )
> 			{
> 				j++;
> 				continue;
> 			}
> 			/* If no values were specified -- delete them all */
> 			if  ( mod->mod_bvalues == NULL ) {
> 
> 				/* found a non matching value - delete it */
> 				ber_bvfree( a->a_vals[j] );
> 				for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
> 					a->a_vals[k - 1] = a->a_vals[k];
> 				}
> 				a->a_vals[k - 1] = NULL;
> 				deleted = 1;
>  			}
> 			else {
> 				/* try matching one of the specified values */
> 
> 
> 				for (i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
> 					if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
> 								a->a_syntax, 3 ) == 0  ) {
> 
> 						/* found a matching value - delete it */
> 						ber_bvfree( a->a_vals[j] );
> 						for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
> 							a->a_vals[k - 1] = a->a_vals[k];
> 						}
> 						a->a_vals[k - 1] = NULL;
> 
> 						deleted = 1;
> 					}
> 				}
> 			}
> 			if (! deleted)
> 				j++;
> 
> 		}   /* end while ... */
> 
> 		free (rdn_value);
> 		free (rdn_type);
> 		free (rdn);
> 		return( LDAP_SUCCESS );
> 	}
> 
> 	free (rdn_type);
> 	free (rdn);
> 
> 	if ( mod->mod_bvalues == NULL ) {
> 		Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
> 				mod->mod_type, 0, 0 );
> 		return( attr_delete( &e->e_attrs, mod->mod_type ) ?
> 					LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
> 	}
> 
259,261c390,394
< 		for ( j = 0; a->a_vals[j] != NULL; j++ ) {
< 			if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
< 			    a->a_syntax, 3 ) != 0 ) {
- ---
> 		j = 0; 
> 		while (a->a_vals[j] != NULL ) {
> 			if ( value_cmp
>                    ( mod->mod_bvalues[i], a->a_vals[j], a->a_syntax, 3 ) != 0 ) {
> 				j++;
271a405
> 		}
273,274c407,408
< 			/* delete the entire attribute, if no values remain */
< 			if ( a->a_vals[0] == NULL) {
- ---
> 		/* delete the entire attribute, if no values remain */
> 		if ( a->a_vals[0] == NULL) {
281,283d414
< 			}
< 
< 			break;
305c436,514
< 	(void) attr_delete( &e->e_attrs, mod->mod_type );
- ---
> 	int		j, k;
> 	Attribute	*a;
> 	int         exists = 0;
> 	char        *rdn, *rdn_type, *rdn_value;
> 	struct berval   val;
> 	struct berval   **changes;
> 
> 	/* If this attribute is part of the dn */
> 	/* then remove all of the attribute values except the rdn value */
> 	rdn = dn_rdn( NULL, e->e_dn );
> 	rdn_type = rdn_attr_type( rdn );
> 	if (rdn_type == NULL ) {
> 		Debug( LDAP_DEBUG_ANY, "Bad RDN type for entry (%s)\n",
> 				e->e_dn, 0, 0 );
> 		free ( rdn );
> 		return( 1 );
> 	}
> 
> 
> 	k = 0;
> 	for ( j = 0; mod->mod_bvalues[j] != NULL; j++ ) {
> 		k++;
> 	}
> 
> 	changes = ch_malloc (j * sizeof (struct berval));
> 	if (! changes) {
> 		Debug( LDAP_DEBUG_ANY, "Bad RDN value for entry (%s)\n",
> 				e->e_dn, 0, 0 );
> 		free ( rdn_type);
> 		free ( rdn);
> 		return( 1 );
> 	}
> 	for ( j = 0; mod->mod_bvalues[j] != NULL; j++ ) {
> 		changes[j] = mod->mod_bvalues[j];
> 	}
> 	changes[j] = NULL;	
> 
> 	if (strcasecmp (rdn_type, mod->mod_type) == 0){
> 
> 		/* find the attribute first */
> 		if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) {
> 			Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
> 					mod->mod_type, 0, 0 );
> 		}
> 		else {
> 			/* Look thru the the current attribute values,  */
> 			/* deleting all but the rdn                     */
> 
> 			rdn_value = rdn_attr_value ( rdn );
> 			if (rdn_value == NULL ) {
> 				Debug( LDAP_DEBUG_ANY, "Bad RDN value for entry (%s)\n",
> 					e->e_dn, 0, 0 );
> 				free ( rdn_type);
> 				free ( rdn);
> 				free ( changes );
> 				return( 1 );
> 			}
> 			val.bv_len = strlen( rdn_value );
> 			val.bv_val = rdn_value;
> 			value_normalize( val.bv_val, attr_syntax( rdn_type ));
> 
> 			j = 0; 
> 			while (a->a_vals[j] != NULL ) {
> 
> 				if ( value_cmp 
>                     (&val, a->a_vals[ j ], attr_syntax( rdn_type ), 2 ) == 0 ) {
> 					j++;
> 					continue;
> 				}
> 
> 				/* found a non matching value - delete it */
> 				ber_bvfree( a->a_vals[j] );
> 				for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
> 						a->a_vals[k - 1] = a->a_vals[k];
> 				}
> 				a->a_vals[k - 1] = NULL;
> 			}   /* end while ... */
> 
> 			free (rdn_value);
307c516,545
< 	if ( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
- ---
> 
> 			/* delete the entire attribute, if no values remain */
> 			if ( a->a_vals[0] == NULL) {
> 				Debug( LDAP_DEBUG_ARGS,
> 					"removing entire attribute %s\n",
> 							mod->mod_type, 0, 0 );
> 				(void) attr_delete( &e->e_attrs, mod->mod_type );
> 			}
> 			else {
> 				/* check if the values we're adding already exist */
> 				for ( j = 0; changes[j] != NULL; j++ ) {
> 					if ( value_find( a->a_vals, changes[j],
> 			    						a->a_syntax, 3 ) == 0 ) {
> 						for ( k = j + 1; changes[k] != NULL; k++ ) {
> 							changes[k - 1] = changes[k];
> 						}
> 						changes[k - 1] = NULL;
> 					}
> 				}
> 			}
> 		}
>     }
>     else    
> 	    (void) attr_delete( &e->e_attrs, mod->mod_type );
> 
> 	free (rdn_type);
> 	free (rdn);
> 
> 	if ( attr_merge( e, mod->mod_type, changes ) != 0 ) {
> 		free ( changes );
310c548
< 
- ---
> 	free ( changes );