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