]> git.sur5r.net Git - openldap/blob - servers/slapd/modrdn.c
import fix to ITS#3474 from HEAD
[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 = BER_BVNULL;
54         struct berval newrdn = BER_BVNULL;
55         struct berval newSuperior = BER_BVNULL;
56         ber_int_t       deloldrdn;
57
58         struct berval pnewSuperior = BER_BVNULL;
59
60         struct berval nnewSuperior = BER_BVNULL;
61
62         Backend *newSuperior_be = NULL;
63         ber_len_t       length;
64         int manageDSAit;
65
66         struct berval pdn = BER_BVNULL;
67         struct berval org_req_dn = BER_BVNULL;
68         struct berval org_req_ndn = BER_BVNULL;
69         struct berval org_dn = BER_BVNULL;
70         struct berval org_ndn = BER_BVNULL;
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         op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 0 );
281         if ( op->o_bd == NULL ) {
282                 rs->sr_ref = referral_rewrite( default_referral,
283                         NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
284                 if (!rs->sr_ref) rs->sr_ref = default_referral;
285
286                 if ( rs->sr_ref != NULL ) {
287                         rs->sr_err = LDAP_REFERRAL;
288                         send_ldap_result( op, rs );
289
290                         if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
291                 } else {
292                         send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
293                                 "no global superior knowledge" );
294                 }
295                 goto cleanup;
296         }
297
298         /* check restrictions */
299         if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
300                 send_ldap_result( op, rs );
301                 goto cleanup;
302         }
303
304         /* check for referrals */
305         if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
306                 goto cleanup;
307         }
308
309         /* Make sure that the entry being changed and the newSuperior are in 
310          * the same backend, otherwise we return an error.
311          */
312         if( op->orr_newSup ) {
313                 newSuperior_be = select_backend( &nnewSuperior, 0, 0 );
314
315                 if ( newSuperior_be != op->o_bd ) {
316                         /* newSuperior is in different backend */
317                         send_ldap_error( op, rs, LDAP_AFFECTS_MULTIPLE_DSAS,
318                                 "cannot rename between DSAs" );
319
320                         goto cleanup;
321                 }
322         }
323
324 #if defined( LDAP_SLAPI )
325 #define pb      op->o_pb
326         if ( pb ) {
327                 slapi_int_pblock_set_operation( pb, op );
328                 slapi_pblock_set( pb, SLAPI_MODRDN_TARGET, (void *)dn.bv_val );
329                 slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn.bv_val );
330                 slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR,
331                                 (void *)newSuperior.bv_val );
332                 slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, (void *)deloldrdn );
333                 slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)manageDSAit );
334
335                 rs->sr_err = slapi_int_call_plugins( op->o_bd, SLAPI_PLUGIN_PRE_MODRDN_FN, pb );
336                 if ( rs->sr_err < 0 ) {
337                         /*
338                          * A preoperation plugin failure will abort the
339                          * entire operation.
340                          */
341 #ifdef NEW_LOGGING
342                         LDAP_LOG( OPERATION, INFO, "do_modrdn: modrdn preoperation plugin "
343                                         "failed\n", 0, 0, 0 );
344 #else
345                         Debug(LDAP_DEBUG_TRACE, "do_modrdn: modrdn preoperation plugin "
346                                         "failed.\n", 0, 0, 0);
347 #endif
348                         if ( ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rs->sr_err ) != 0 ) ||
349                                  rs->sr_err == LDAP_SUCCESS ) {
350                                 rs->sr_err = LDAP_OTHER;
351                         }
352                         goto cleanup;
353                 }
354         }
355 #endif /* defined( LDAP_SLAPI ) */
356
357         /*
358          * do the modrdn if 1 && (2 || 3)
359          * 1) there is a modrdn function implemented in this backend;
360          * 2) this backend is master for what it holds;
361          * 3) it's a replica and the dn supplied is the update_ndn.
362          */
363         if ( op->o_bd->be_modrdn ) {
364                 /* do the update here */
365                 int repl_user = be_isupdate( op );
366 #ifndef SLAPD_MULTIMASTER
367                 if ( !SLAP_SHADOW(op->o_bd) || repl_user )
368 #endif
369                 {
370                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
371                         op->orr_deleteoldrdn = deloldrdn;
372 #ifdef SLAPD_MULTIMASTER
373                         if ( !op->o_bd->be_update_ndn.bv_len || !repl_user )
374 #endif
375                         {
376                                 cb.sc_next = op->o_callback;
377                                 op->o_callback = &cb;
378                         }
379                         op->o_bd->be_modrdn( op, rs );
380
381                         if ( op->o_bd->be_delete ) {
382                                 org_req_dn = op->o_req_dn;
383                                 org_req_ndn = op->o_req_ndn;
384                                 org_dn = op->o_dn;
385                                 org_ndn = op->o_ndn;
386                                 org_managedsait = get_manageDSAit( op );
387                                 op->o_dn = op->o_bd->be_rootdn;
388                                 op->o_ndn = op->o_bd->be_rootndn;
389                                 op->o_managedsait = 1;
390
391                                 while ( rs->sr_err == LDAP_SUCCESS &&
392                                                 op->o_delete_glue_parent ) {
393                         op->o_delete_glue_parent = 0;
394                                         if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
395                                                 slap_callback cb = { NULL };
396                                                 cb.sc_response = slap_null_cb;
397                                                 dnParent( &op->o_req_ndn, &pdn );
398                                                 op->o_req_dn = pdn;
399                                                 op->o_req_ndn = pdn;
400                                                 op->o_callback = &cb;
401                                                 op->o_bd->be_delete( op, rs );
402                                         } else {
403                                                 break;
404                                         }
405                                 }
406                                 op->o_managedsait = org_managedsait;
407                     op->o_dn = org_dn;
408                                 op->o_ndn = org_ndn;
409                                 op->o_req_dn = org_req_dn;
410                                 op->o_req_ndn = org_req_ndn;
411                                 op->o_delete_glue_parent = 0;
412                         }
413
414 #ifndef SLAPD_MULTIMASTER
415                 } else {
416                         BerVarray defref = op->o_bd->be_update_refs
417                                 ? op->o_bd->be_update_refs : default_referral;
418
419                         if ( defref != NULL ) {
420                                 rs->sr_ref = referral_rewrite( defref,
421                                         NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
422                                 if (!rs->sr_ref) rs->sr_ref = defref;
423
424                                 rs->sr_err = LDAP_REFERRAL;
425                                 send_ldap_result( op, rs );
426
427                                 if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref );
428                         } else {
429                                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
430                                         "shadow context; no update referral" );
431                         }
432 #endif
433                 }
434         } else {
435                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
436                         "operation not supported within namingContext" );
437         }
438
439 #if defined( LDAP_SLAPI )
440         if ( pb != NULL && slapi_int_call_plugins( op->o_bd, SLAPI_PLUGIN_POST_MODRDN_FN, pb ) < 0 ) {
441 #ifdef NEW_LOGGING
442                 LDAP_LOG( OPERATION, INFO, "do_modrdn: modrdn postoperation plugins "
443                                 "failed\n", 0, 0, 0 );
444 #else
445                 Debug(LDAP_DEBUG_TRACE, "do_modrdn: modrdn postoperation plugins "
446                                 "failed.\n", 0, 0, 0);
447 #endif
448         }
449 #endif /* defined( LDAP_SLAPI ) */
450
451 cleanup:
452
453         slap_graduate_commit_csn( op );
454
455         op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
456         op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
457
458         op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );        
459         op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );       
460
461         if ( pnewSuperior.bv_val ) op->o_tmpfree( pnewSuperior.bv_val, op->o_tmpmemctx );
462         if ( nnewSuperior.bv_val ) op->o_tmpfree( nnewSuperior.bv_val, op->o_tmpmemctx );
463
464         return rs->sr_err;
465 }
466
467 int
468 slap_modrdn2mods(
469         Operation       *op,
470         SlapReply       *rs,
471         Entry           *e,
472         LDAPRDN         old_rdn,
473         LDAPRDN         new_rdn,
474         Modifications   **pmod )
475 {
476         Modifications   *mod = NULL;
477         Modifications   **modtail = &mod;
478         int             a_cnt, d_cnt;
479         int repl_user;
480
481         assert( new_rdn != NULL );
482         assert( !op->orr_deleteoldrdn || old_rdn != NULL );
483
484         repl_user = be_isupdate( op );
485
486         /* Add new attribute values to the entry */
487         for ( a_cnt = 0; new_rdn[a_cnt]; a_cnt++ ) {
488                 AttributeDescription    *desc = NULL;
489                 Modifications           *mod_tmp;
490
491                 rs->sr_err = slap_bv2ad( &new_rdn[a_cnt]->la_attr, &desc, &rs->sr_text );
492
493                 if ( rs->sr_err != LDAP_SUCCESS ) {
494 #ifdef NEW_LOGGING
495                         LDAP_LOG ( OPERATION, ERR, 
496                                 "slap_modrdn2modlist: %s: %s (new)\n", 
497                                 rs->sr_text, 
498                                 new_rdn[ a_cnt ]->la_attr.bv_val, 0 );
499 #else
500                         Debug( LDAP_DEBUG_TRACE,
501                                 "slap_modrdn2modlist: %s: %s (new)\n",
502                                 rs->sr_text, 
503                                 new_rdn[ a_cnt ]->la_attr.bv_val, 0 );
504 #endif
505                         goto done;              
506                 }
507
508                 /* ACL check of newly added attrs */
509                 if ( op->o_bd && !access_allowed( op, e, desc,
510                         &new_rdn[a_cnt]->la_value, ACL_WRITE, NULL ) ) {
511 #ifdef NEW_LOGGING
512                         LDAP_LOG ( OPERATION, ERR, 
513                                 "slap_modrdn2modlist: access to attr \"%s\" "
514                                 "(new) not allowed\n", 
515                                 new_rdn[a_cnt]->la_attr.bv_val, 0, 0 );
516 #else
517                         Debug( LDAP_DEBUG_TRACE,
518                                 "slap_modrdn2modlist: access to attr \"%s\" "
519                                 "(new) not allowed\n", 
520                                 new_rdn[ a_cnt ]->la_attr.bv_val, 0, 0 );
521 #endif
522                         rs->sr_text = "access to naming attributes (new) not allowed";
523                         rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
524                         goto done;
525                 }
526
527                 /* Apply modification */
528                 mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications )
529                         + 4 * sizeof( struct berval ) );
530                 mod_tmp->sml_desc = desc;
531                 mod_tmp->sml_values = ( BerVarray )( mod_tmp + 1 );
532                 mod_tmp->sml_values[0] = new_rdn[a_cnt]->la_value;
533                 mod_tmp->sml_values[1].bv_val = NULL;
534                 if( desc->ad_type->sat_equality->smr_normalize) {
535                         mod_tmp->sml_nvalues = &mod_tmp->sml_values[2];
536                         (void) (*desc->ad_type->sat_equality->smr_normalize)(
537                                 SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
538                                 desc->ad_type->sat_syntax,
539                                 desc->ad_type->sat_equality,
540                                 &mod_tmp->sml_values[0],
541                                 &mod_tmp->sml_nvalues[0], NULL );
542                         mod_tmp->sml_nvalues[1].bv_val = NULL;
543                 } else {
544                         mod_tmp->sml_nvalues = NULL;
545                 }
546                 mod_tmp->sml_op = SLAP_MOD_SOFTADD;
547                 mod_tmp->sml_next = mod;
548                 mod = mod_tmp;
549         }
550
551         /* Remove old rdn value if required */
552         if ( op->orr_deleteoldrdn ) {
553                 for ( d_cnt = 0; old_rdn[d_cnt]; d_cnt++ ) {
554                         AttributeDescription    *desc = NULL;
555                         Modifications           *mod_tmp;
556
557                         rs->sr_err = slap_bv2ad( &old_rdn[d_cnt]->la_attr, &desc, &rs->sr_text );
558                         if ( rs->sr_err != LDAP_SUCCESS ) {
559 #ifdef NEW_LOGGING
560                                 LDAP_LOG ( OPERATION, ERR, 
561                                         "slap_modrdn2modlist: %s: %s (old)\n", 
562                                         rs->sr_text, 
563                                         old_rdn[d_cnt]->la_attr.bv_val, 
564                                         0 );
565 #else
566                                 Debug( LDAP_DEBUG_TRACE,
567                                         "slap_modrdn2modlist: %s: %s (old)\n",
568                                         rs->sr_text, 
569                                         old_rdn[d_cnt]->la_attr.bv_val, 
570                                         0 );
571 #endif
572                                 goto done;              
573                         }
574
575                         /* ACL check of newly added attrs */
576                         if ( op->o_bd && !access_allowed( op, e, desc,
577                                 &old_rdn[d_cnt]->la_value, ACL_WRITE, 
578                                 NULL ) ) {
579 #ifdef NEW_LOGGING
580                                 LDAP_LOG ( OPERATION, ERR, 
581                                         "slap_modrdn2modlist: access "
582                                         "to attr \"%s\" (old) not allowed\n", 
583                                         old_rdn[ d_cnt ]->la_attr.bv_val, 
584                                         0, 0 );
585 #else
586                                 Debug( LDAP_DEBUG_TRACE,
587                                         "slap_modrdn2modlist: access "
588                                         "to attr \"%s\" (old) not allowed\n", 
589                                         old_rdn[ d_cnt ]->la_attr.bv_val,
590                                         0, 0 );
591 #endif
592                                 rs->sr_text = "access to naming attributes (old) not allowed";
593                                 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
594                                 goto done;
595                         }
596
597                         /* Apply modification */
598                         mod_tmp = ( Modifications * )ch_malloc( sizeof( Modifications )
599                                 + 4 * sizeof ( struct berval ) );
600                         mod_tmp->sml_desc = desc;
601                         mod_tmp->sml_values = ( BerVarray )(mod_tmp+1);
602                         mod_tmp->sml_values[0] = old_rdn[d_cnt]->la_value;
603                         mod_tmp->sml_values[1].bv_val = NULL;
604                         if( desc->ad_type->sat_equality->smr_normalize) {
605                                 mod_tmp->sml_nvalues = &mod_tmp->sml_values[2];
606                                 (void) (*desc->ad_type->sat_equality->smr_normalize)(
607                                         SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
608                                         desc->ad_type->sat_syntax,
609                                         desc->ad_type->sat_equality,
610                                         &mod_tmp->sml_values[0],
611                                         &mod_tmp->sml_nvalues[0], op->o_tmpmemctx );
612                                 mod_tmp->sml_nvalues[1].bv_val = NULL;
613                         } else {
614                                 mod_tmp->sml_nvalues = NULL;
615                         }
616                         mod_tmp->sml_op = LDAP_MOD_DELETE;
617                         mod_tmp->sml_next = mod;
618                         mod = mod_tmp;
619                 }
620         }
621         
622 done:
623
624         if ( rs->sr_err == LDAP_SUCCESS && !repl_user ) {
625                 char textbuf[ SLAP_TEXT_BUFLEN ];
626                 size_t textlen = sizeof textbuf;
627
628                 for( modtail = &mod;
629                         *modtail != NULL;
630                         modtail = &(*modtail)->sml_next )
631                 {
632                         /* empty */
633                 }
634
635                 rs->sr_err = slap_mods_opattrs( op, mod, modtail,
636                                                 &rs->sr_text, textbuf, textlen, 1 );
637         }
638
639         /* LDAP v2 supporting correct attribute handling. */
640         if ( rs->sr_err != LDAP_SUCCESS && mod != NULL ) {
641                 Modifications *tmp;
642                 for ( ; mod; mod = tmp ) {
643                         tmp = mod->sml_next;
644                         ch_free( mod );
645                 }
646         }
647
648         *pmod = mod;
649
650         return rs->sr_err;
651 }