]> git.sur5r.net Git - openldap/blob - servers/slapd/modrdn.c
ITS#2368 - fix deleting key from range IDL
[openldap] / servers / slapd / modrdn.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1995 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 /*
19  * LDAP v3 newSuperior support.
20  *
21  * Copyright 1999, Juan C. Gomez, All rights reserved.
22  * This software is not subject to any license of Silicon Graphics 
23  * Inc. or Purdue University.
24  *
25  * Redistribution and use in source and binary forms are permitted
26  * without restriction or fee of any kind as long as this notice
27  * is preserved.
28  *
29  */
30
31 #include "portable.h"
32
33 #include <stdio.h>
34
35 #include <ac/socket.h>
36 #include <ac/string.h>
37
38 #include "ldap_pvt.h"
39 #include "slap.h"
40 #ifdef LDAP_SLAPI
41 #include "slapi.h"
42 #endif
43
44 int
45 do_modrdn(
46     Connection  *conn,
47     Operation   *op
48 )
49 {
50         struct berval dn = { 0, NULL };
51         struct berval newrdn = { 0, NULL };
52         struct berval newSuperior = { 0, NULL };
53         ber_int_t       deloldrdn;
54
55         struct berval pdn = { 0, NULL };
56         struct berval pnewrdn = { 0, NULL };
57         struct berval pnewSuperior = { 0, NULL }, *pnewS = NULL;
58
59         struct berval ndn = { 0, NULL };
60         struct berval nnewrdn = { 0, NULL };
61         struct berval nnewSuperior = { 0, NULL }, *nnewS = NULL;
62
63         Backend *be;
64         Backend *newSuperior_be = NULL;
65         ber_len_t       length;
66         int rc;
67         const char *text;
68         int manageDSAit;
69
70 #ifdef LDAP_SLAPI
71         Slapi_PBlock *pb = op->o_pb;
72 #endif
73
74 #ifdef NEW_LOGGING
75         LDAP_LOG( OPERATION, ENTRY, "do_modrdn: begin\n", 0, 0, 0 );
76 #else
77         Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
78 #endif
79
80
81         /*
82          * Parse the modrdn request.  It looks like this:
83          *
84          *      ModifyRDNRequest := SEQUENCE {
85          *              entry   DistinguishedName,
86          *              newrdn  RelativeDistinguishedName
87          *              deleteoldrdn    BOOLEAN,
88          *              newSuperior     [0] LDAPDN OPTIONAL (v3 Only!)
89          *      }
90          */
91
92         if ( ber_scanf( op->o_ber, "{mmb", &dn, &newrdn, &deloldrdn )
93             == LBER_ERROR )
94         {
95 #ifdef NEW_LOGGING
96                 LDAP_LOG( OPERATION, ERR, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
97 #else
98                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
99 #endif
100
101                 send_ldap_disconnect( conn, op,
102                         LDAP_PROTOCOL_ERROR, "decoding error" );
103                 return SLAPD_DISCONNECT;
104         }
105
106         /* Check for newSuperior parameter, if present scan it */
107
108         if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
109                 if ( op->o_protocol < LDAP_VERSION3 ) {
110                         /* Conection record indicates v2 but field 
111                          * newSuperior is present: report error.
112                          */
113 #ifdef NEW_LOGGING
114                         LDAP_LOG( OPERATION, ERR,
115                                 "do_modrdn: (v2) invalid field newSuperior.\n", 0, 0, 0 );
116 #else
117                         Debug( LDAP_DEBUG_ANY,
118                             "modrdn(v2): invalid field newSuperior!\n",
119                             0, 0, 0 );
120 #endif
121
122                         send_ldap_disconnect( conn, op,
123                                 LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
124                         rc = SLAPD_DISCONNECT;
125                         goto cleanup;
126                 }
127
128                 if ( ber_scanf( op->o_ber, "m", &newSuperior ) 
129                      == LBER_ERROR ) {
130
131 #ifdef NEW_LOGGING
132                         LDAP_LOG( OPERATION, ERR,
133                                 "do_modrdn: ber_scanf(\"m\") failed\n", 0, 0, 0 );
134 #else
135                         Debug( LDAP_DEBUG_ANY, "ber_scanf(\"m\") failed\n",
136                                 0, 0, 0 );
137 #endif
138
139                         send_ldap_disconnect( conn, op,
140                                 LDAP_PROTOCOL_ERROR, "decoding error" );
141                         rc = SLAPD_DISCONNECT;
142                         goto cleanup;
143                 }
144                 pnewS = &pnewSuperior;
145                 nnewS = &nnewSuperior;
146         }
147
148 #ifdef NEW_LOGGING
149         LDAP_LOG( OPERATION, ARGS, 
150                 "do_modrdn: dn (%s) newrdn (%s) newsuperior(%s)\n",
151                 dn.bv_val, newrdn.bv_val,
152                 newSuperior.bv_len ? newSuperior.bv_val : "" );
153 #else
154         Debug( LDAP_DEBUG_ARGS,
155             "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
156                 dn.bv_val, newrdn.bv_val,
157                 newSuperior.bv_len ? newSuperior.bv_val : "" );
158 #endif
159
160         if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
161 #ifdef NEW_LOGGING
162                 LDAP_LOG( OPERATION, ERR, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
163 #else
164                 Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
165 #endif
166
167                 send_ldap_disconnect( conn, op,
168                         LDAP_PROTOCOL_ERROR, "decoding error" );
169                 rc = SLAPD_DISCONNECT;
170                 goto cleanup;
171         }
172
173         if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
174 #ifdef NEW_LOGGING
175                 LDAP_LOG( OPERATION, ERR, "do_modrdn: get_ctrls failed\n", 0, 0, 0 );
176 #else
177                 Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 );
178 #endif
179
180                 /* get_ctrls has sent results.  Now clean up. */
181                 goto cleanup;
182         } 
183
184         rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn );
185         if( rc != LDAP_SUCCESS ) {
186 #ifdef NEW_LOGGING
187                 LDAP_LOG( OPERATION, INFO, 
188                         "do_modrdn: conn %d  invalid dn (%s)\n",
189                         conn->c_connid, dn.bv_val, 0 );
190 #else
191                 Debug( LDAP_DEBUG_ANY,
192                         "do_modrdn: invalid dn (%s)\n", dn.bv_val, 0, 0 );
193 #endif
194                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
195                     "invalid DN", NULL, NULL );
196                 goto cleanup;
197         }
198
199         if( ndn.bv_len == 0 ) {
200 #ifdef NEW_LOGGING
201                 LDAP_LOG( OPERATION, ERR,
202                         "do_modrdn:  attempt to modify root DSE.\n", 0, 0, 0 );
203 #else
204                 Debug( LDAP_DEBUG_ANY, "do_modrdn: root dse!\n", 0, 0, 0 );
205 #endif
206
207                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
208                         NULL, "cannot rename the root DSE", NULL, NULL );
209                 goto cleanup;
210
211         } else if ( bvmatch( &ndn, &global_schemandn ) ) {
212 #ifdef NEW_LOGGING
213                 LDAP_LOG( OPERATION, ERR,
214                         "do_modrdn: attempt to modify subschema subentry: %s (%ld)\n",
215                         global_schemandn.bv_val, (long) global_schemandn.bv_len, 0 );
216 #else
217                 Debug( LDAP_DEBUG_ANY, "do_modrdn: subschema subentry: %s (%ld)\n",
218                         global_schemandn.bv_val, (long) global_schemandn.bv_len, 0 );
219 #endif
220
221                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
222                         NULL, "cannot rename subschema subentry", NULL, NULL );
223                 goto cleanup;
224         }
225
226         /* FIXME: should have/use rdnPretty / rdnNormalize routines */
227
228         rc = dnPrettyNormal( NULL, &newrdn, &pnewrdn, &nnewrdn );
229         if( rc != LDAP_SUCCESS ) {
230 #ifdef NEW_LOGGING
231                 LDAP_LOG( OPERATION, INFO, 
232                         "do_modrdn: conn %d  invalid newrdn (%s)\n",
233                         conn->c_connid, newrdn.bv_val, 0 );
234 #else
235                 Debug( LDAP_DEBUG_ANY,
236                         "do_modrdn: invalid newrdn (%s)\n", newrdn.bv_val, 0, 0 );
237 #endif
238                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
239                     "invalid new RDN", NULL, NULL );
240                 goto cleanup;
241         }
242
243         if( rdnValidate( &pnewrdn ) != LDAP_SUCCESS ) {
244 #ifdef NEW_LOGGING
245                 LDAP_LOG( OPERATION, ERR, 
246                         "do_modrdn: invalid rdn (%s).\n", pnewrdn.bv_val, 0, 0 );
247 #else
248                 Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid rdn (%s)\n",
249                         pnewrdn.bv_val, 0, 0 );
250 #endif
251
252                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
253                     "invalid new RDN", NULL, NULL );
254                 goto cleanup;
255         }
256
257         if( pnewS ) {
258                 rc = dnPrettyNormal( NULL, &newSuperior, &pnewSuperior,
259                         &nnewSuperior );
260                 if( rc != LDAP_SUCCESS ) {
261 #ifdef NEW_LOGGING
262                         LDAP_LOG( OPERATION, INFO, 
263                                 "do_modrdn: conn %d  invalid newSuperior (%s)\n",
264                                 conn->c_connid, newSuperior.bv_val, 0 );
265 #else
266                         Debug( LDAP_DEBUG_ANY,
267                                 "do_modrdn: invalid newSuperior (%s)\n",
268                                 newSuperior.bv_val, 0, 0 );
269 #endif
270                         send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
271                                 "invalid newSuperior", NULL, NULL );
272                         goto cleanup;
273                 }
274         }
275
276         Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MODRDN dn=\"%s\"\n",
277             op->o_connid, op->o_opid, pdn.bv_val, 0, 0 );
278
279         manageDSAit = get_manageDSAit( op );
280
281         /*
282          * We could be serving multiple database backends.  Select the
283          * appropriate one, or send a referral to our "referral server"
284          * if we don't hold it.
285          */
286         if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) {
287                 BerVarray ref = referral_rewrite( default_referral,
288                         NULL, &pdn, LDAP_SCOPE_DEFAULT );
289
290                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
291                         NULL, NULL, ref ? ref : default_referral, NULL );
292
293                 ber_bvarray_free( ref );
294                 goto cleanup;
295         }
296
297         /* check restrictions */
298         rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
299         if( rc != LDAP_SUCCESS ) {
300                 send_ldap_result( conn, op, rc,
301                         NULL, text, NULL, NULL );
302                 goto cleanup;
303         }
304
305         /* check for referrals */
306         rc = backend_check_referrals( be, conn, op, &pdn, &ndn );
307         if ( rc != LDAP_SUCCESS ) {
308                 goto cleanup;
309         }
310
311         /* Make sure that the entry being changed and the newSuperior are in 
312          * the same backend, otherwise we return an error.
313          */
314         if( pnewS ) {
315                 newSuperior_be = select_backend( &nnewSuperior, 0, 0 );
316
317                 if ( newSuperior_be != be ) {
318                         /* newSuperior is in same backend */
319                         rc = LDAP_AFFECTS_MULTIPLE_DSAS;
320
321                         send_ldap_result( conn, op, rc,
322                                 NULL, "cannot rename between DSAa", NULL, NULL );
323
324                         goto cleanup;
325                 }
326         }
327
328 #if defined( LDAP_SLAPI )
329         slapi_x_backend_set_pb( pb, be );
330         slapi_x_connection_set_pb( pb, conn );
331         slapi_x_operation_set_pb( pb, op );
332         slapi_pblock_set( pb, SLAPI_MODRDN_TARGET, (void *)dn.bv_val );
333         slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn.bv_val );
334         slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR,
335                         (void *)newSuperior.bv_val );
336         slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, (void *)deloldrdn );
337         slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)manageDSAit );
338
339         rc = doPluginFNs( be, SLAPI_PLUGIN_PRE_MODRDN_FN, pb );
340         if ( rc != 0 ) {
341                 /*
342                  * A preoperation plugin failure will abort the
343                  * entire operation.
344                  */
345 #ifdef NEW_LOGGING
346                 LDAP_LOG( OPERATION, INFO, "do_modrdn: modrdn preoperation plugin "
347                                 "failed\n", 0, 0, 0 );
348 #else
349                 Debug(LDAP_DEBUG_TRACE, "do_modrdn: modrdn preoperation plugin "
350                                 "failed.\n", 0, 0, 0);
351 #endif
352                 if ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rc ) != 0)
353                         rc = LDAP_OTHER;
354                 goto cleanup;
355         }
356 #endif /* defined( LDAP_SLAPI ) */
357
358         /*
359          * do the add if 1 && (2 || 3)
360          * 1) there is an add function implemented in this backend;
361          * 2) this backend is master for what it holds;
362          * 3) it's a replica and the dn supplied is the update_ndn.
363          */
364         if ( be->be_modrdn ) {
365                 /* do the update here */
366                 int repl_user = be_isupdate( be, &op->o_ndn );
367 #ifndef SLAPD_MULTIMASTER
368                 if ( !be->be_update_ndn.bv_len || repl_user )
369 #endif
370                 {
371                         if ( (*be->be_modrdn)( be, conn, op, &pdn, &ndn,
372                                 &pnewrdn, &nnewrdn, deloldrdn,
373                                 pnewS, nnewS ) == 0
374 #ifdef SLAPD_MULTIMASTER
375                                 && ( !be->be_update_ndn.bv_len || !repl_user )
376 #endif
377                         ) {
378                                 struct slap_replog_moddn moddn;
379                                 moddn.newrdn = &pnewrdn;
380                                 moddn.deloldrdn = deloldrdn;
381                                 moddn.newsup = &pnewSuperior;
382
383                                 replog( be, op, &pdn, &ndn, &moddn );
384                         }
385 #ifndef SLAPD_MULTIMASTER
386                 } else {
387                         BerVarray defref = be->be_update_refs
388                                 ? be->be_update_refs : default_referral;
389                         BerVarray ref = referral_rewrite( defref,
390                                 NULL, &pdn, LDAP_SCOPE_DEFAULT );
391
392                         send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
393                                 ref ? ref : defref, NULL );
394
395                         ber_bvarray_free( ref );
396 #endif
397                 }
398         } else {
399                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
400                         NULL, "operation not supported within namingContext",
401                         NULL, NULL );
402         }
403
404 #if defined( LDAP_SLAPI )
405         if ( doPluginFNs( be, SLAPI_PLUGIN_POST_MODRDN_FN, pb ) != 0 ) {
406 #ifdef NEW_LOGGING
407                 LDAP_LOG( OPERATION, INFO, "do_modrdn: modrdn postoperation plugins "
408                                 "failed\n", 0, 0, 0 );
409 #else
410                 Debug(LDAP_DEBUG_TRACE, "do_modrdn: modrdn postoperation plugins "
411                                 "failed.\n", 0, 0, 0);
412 #endif
413         }
414 #endif /* defined( LDAP_SLAPI ) */
415
416 cleanup:
417         free( pdn.bv_val );
418         free( ndn.bv_val );
419
420         free( pnewrdn.bv_val ); 
421         free( nnewrdn.bv_val ); 
422
423         if ( pnewSuperior.bv_val ) free( pnewSuperior.bv_val );
424         if ( nnewSuperior.bv_val ) free( nnewSuperior.bv_val );
425
426         return rc;
427 }
428
429 int
430 slap_modrdn2mods(
431         Backend         *be,
432         Connection      *conn,
433         Operation       *op,
434         Entry           *e,
435         LDAPRDN         *old_rdn,
436         LDAPRDN         *new_rdn,
437         int             deleteoldrdn,
438         Modifications   **pmod )
439 {
440         int             rc = LDAP_SUCCESS;
441         const char      *text;
442         Modifications   *mod = NULL;
443         int             a_cnt, d_cnt;
444
445         assert( new_rdn != NULL );
446         assert( !deleteoldrdn || old_rdn != NULL );
447
448         /* Add new attribute values to the entry */
449         for ( a_cnt = 0; new_rdn[0][a_cnt]; a_cnt++ ) {
450                 AttributeDescription    *desc = NULL;
451                 Modifications           *mod_tmp;
452
453                 rc = slap_bv2ad( &new_rdn[0][a_cnt]->la_attr, &desc, &text );
454
455                 if ( rc != LDAP_SUCCESS ) {
456 #ifdef NEW_LOGGING
457                         LDAP_LOG ( OPERATION, ERR, 
458                                 "slap_modrdn2modlist: %s: %s (new)\n", 
459                                 text, 
460                                 new_rdn[ 0 ][ a_cnt ]->la_attr.bv_val, 0 );
461 #else
462                         Debug( LDAP_DEBUG_TRACE,
463                                 "slap_modrdn2modlist: %s: %s (new)\n",
464                                 text, 
465                                 new_rdn[ 0 ][ a_cnt ]->la_attr.bv_val, 0 );
466 #endif
467                         goto done;              
468                 }
469
470                 /* ACL check of newly added attrs */
471                 if ( be && !access_allowed( be, conn, op, e, desc,
472                         &new_rdn[0][a_cnt]->la_value, ACL_WRITE, NULL ) ) {
473 #ifdef NEW_LOGGING
474                         LDAP_LOG ( OPERATION, ERR, 
475                                 "slap_modrdn2modlist: access to attr \"%s\" "
476                                 "(new) not allowed\n", 
477                                 new_rdn[0][a_cnt]->la_attr.bv_val, 0, 0 );
478 #else
479                         Debug( LDAP_DEBUG_TRACE,
480                                 "slap_modrdn2modlist: access to attr \"%s\" "
481                                 "(new) not allowed\n", 
482                                 new_rdn[0][ a_cnt ]->la_attr.bv_val, 0, 0 );
483 #endif
484                         rc = LDAP_INSUFFICIENT_ACCESS;
485                         goto done;
486                 }
487
488                 /* Apply modification */
489 #ifdef SLAP_NVALUES
490                 mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications )
491                         + 4 * sizeof( struct berval ) );
492 #else
493                 mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications )
494                         + 2 * sizeof( struct berval ) );
495 #endif
496                 mod_tmp->sml_desc = desc;
497                 mod_tmp->sml_values = ( BerVarray )( mod_tmp + 1 );
498                 mod_tmp->sml_values[0] = new_rdn[0][a_cnt]->la_value;
499                 mod_tmp->sml_values[1].bv_val = NULL;
500 #ifdef SLAP_NVALUES
501                 if( desc->ad_type->sat_equality->smr_normalize) {
502                         mod_tmp->sml_nvalues = &mod_tmp->sml_values[2];
503                         (void) (*desc->ad_type->sat_equality->smr_normalize)(
504                                 SLAP_MR_EQUALITY,
505                                 desc->ad_type->sat_syntax,
506                                 desc->ad_type->sat_equality,
507                                 &mod_tmp->sml_values[0],
508                                 &mod_tmp->sml_nvalues[0] );
509                         mod_tmp->sml_nvalues[1].bv_val = NULL;
510                 } else {
511                         mod_tmp->sml_nvalues = NULL;
512                 }
513 #endif
514                 mod_tmp->sml_op = SLAP_MOD_SOFTADD;
515                 mod_tmp->sml_next = mod;
516                 mod = mod_tmp;
517         }
518
519         /* Remove old rdn value if required */
520         if ( deleteoldrdn ) {
521                 for ( d_cnt = 0; old_rdn[0][d_cnt]; d_cnt++ ) {
522                         AttributeDescription    *desc = NULL;
523                         Modifications           *mod_tmp;
524
525                         rc = slap_bv2ad( &old_rdn[0][d_cnt]->la_attr, &desc, &text );
526                         if ( rc != LDAP_SUCCESS ) {
527 #ifdef NEW_LOGGING
528                                 LDAP_LOG ( OPERATION, ERR, 
529                                         "slap_modrdn2modlist: %s: %s (old)\n", 
530                                         text, 
531                                         old_rdn[0][d_cnt]->la_attr.bv_val, 
532                                         0 );
533 #else
534                                 Debug( LDAP_DEBUG_TRACE,
535                                         "slap_modrdn2modlist: %s: %s (old)\n",
536                                         text, 
537                                         old_rdn[0][d_cnt]->la_attr.bv_val, 
538                                         0 );
539 #endif
540                                 goto done;              
541                         }
542
543                         /* ACL check of newly added attrs */
544                         if ( be && !access_allowed( be, conn, op, e, desc,
545                                 &old_rdn[0][d_cnt]->la_value, ACL_WRITE, 
546                                 NULL ) ) {
547 #ifdef NEW_LOGGING
548                                 LDAP_LOG ( OPERATION, ERR, 
549                                         "slap_modrdn2modlist: access "
550                                         "to attr \"%s\" (old) not allowed\n", 
551                                         old_rdn[ 0 ][ d_cnt ]->la_attr.bv_val, 
552                                         0, 0 );
553 #else
554                                 Debug( LDAP_DEBUG_TRACE,
555                                         "slap_modrdn2modlist: access "
556                                         "to attr \"%s\" (old) not allowed\n", 
557                                         old_rdn[ 0 ][ d_cnt ]->la_attr.bv_val,
558                                         0, 0 );
559 #endif
560                                 rc = LDAP_INSUFFICIENT_ACCESS;
561                                 goto done;
562                         }
563
564                         /* Apply modification */
565 #ifdef SLAP_NVALUES
566                         mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications )
567                                 + 2 * sizeof ( struct berval ) );
568 #else
569                         mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications )
570                                 + 2 * sizeof ( struct berval ) );
571 #endif
572                         mod_tmp->sml_desc = desc;
573                         mod_tmp->sml_values = ( BerVarray )(mod_tmp+1);
574                         mod_tmp->sml_values[0] = old_rdn[0][d_cnt]->la_value;
575                         mod_tmp->sml_values[1].bv_val = NULL;
576 #ifdef SLAP_NVALUES
577                         if( desc->ad_type->sat_equality->smr_normalize) {
578                                 mod_tmp->sml_nvalues = &mod_tmp->sml_values[2];
579                                 (void) (*desc->ad_type->sat_equality->smr_normalize)(
580                                         SLAP_MR_EQUALITY,
581                                         desc->ad_type->sat_syntax,
582                                         desc->ad_type->sat_equality,
583                                         &mod_tmp->sml_values[0],
584                                         &mod_tmp->sml_nvalues[0] );
585                                 mod_tmp->sml_nvalues[1].bv_val = NULL;
586                         } else {
587                                 mod_tmp->sml_nvalues = NULL;
588                         }
589 #endif
590                         mod_tmp->sml_op = LDAP_MOD_DELETE;
591                         mod_tmp->sml_next = mod;
592                         mod = mod_tmp;
593                 }
594         }
595         
596 done:
597         /* LDAP v2 supporting correct attribute handling. */
598         if ( rc != LDAP_SUCCESS && mod != NULL ) {
599                 Modifications *tmp;
600                 for ( ; mod; mod = tmp ) {
601                         tmp = mod->sml_next;
602                         ch_free( mod );
603                 }
604         }
605
606         *pmod = mod;
607
608         return rc;
609 }