modrdn.c 22.6 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* modrdn.c - ldbm backend modrdn routine */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7

8
/*
9
10
11
12
 * LDAP v3 newSuperior support. Add new rdn as an attribute.
 * (Full support for v2 also used software/ideas contributed
 * by Roy Hooper rhooper@cyberus.ca, thanks to him for his
 * submission!.)
13
14
15
16
17
18
19
20
21
22
23
 *
 * Copyright 1999, Juan C. Gomez, All rights reserved.
 * This software is not subject to any license of Silicon Graphics 
 * Inc. or Purdue University.
 *
 * Redistribution and use in source and binary forms are permitted
 * without restriction or fee of any kind as long as this notice
 * is preserved.
 *
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
24
25
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
29
30

#include <ac/string.h>
#include <ac/socket.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
31
32
#include "slap.h"
#include "back-ldbm.h"
33
#include "proto-back-ldbm.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
36
37
38
39

int
ldbm_back_modrdn(
    Backend	*be,
    Connection	*conn,
    Operation	*op,
40
41
42
43
    struct berval	*dn,
    struct berval	*ndn,
    struct berval	*newrdn,
    struct berval	*nnewrdn,
44
    int		deleteoldrdn,
45
46
    struct berval	*newSuperior,
    struct berval	*nnewSuperior
Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
48
)
{
49
	AttributeDescription *children = slap_schema.si_ad_children;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
50
	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
51
52
	struct berval	p_dn, p_ndn;
	struct berval	new_dn = { 0, NULL}, *new_ndn = NULL;
53
	Entry		*e, *p = NULL;
54
	Entry		*matched;
55
	int		isroot = -1;
56
57
58
59
60
	int		rootlock = 0;
#define CAN_ROLLBACK	-1
#define MUST_DESTROY	1
	int		rc = CAN_ROLLBACK;
	int 		rc_id = 0;
61
	ID              id = NOID;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
	const char *text = NULL;
63
64
	char textbuf[SLAP_TEXT_BUFLEN];
	size_t textlen = sizeof textbuf;
65
	/* Added to support LDAP v2 correctly (deleteoldrdn thing) */
66
67
68
	char            **new_rdn_vals = NULL;  /* Vals of new rdn */
	char		**new_rdn_types = NULL;	/* Types of new rdn */
	int             a_cnt, d_cnt;
Gary Williams's avatar
Gary Williams committed
69
	char		*old_rdn = NULL;	/* Old rdn's attr type & val */
70
71
	char		**old_rdn_types = NULL;	/* Types of old rdn attrs. */
	char		**old_rdn_vals = NULL;	/* Old rdn attribute values */
Juan Gomez's avatar
Juan Gomez committed
72
73
	/* Added to support newSuperior */ 
	Entry		*np = NULL;	/* newSuperior Entry */
74
75
76
	struct berval	*np_dn = NULL;	/* newSuperior dn */
	struct berval	*np_ndn = NULL; /* newSuperior ndn */
	struct berval	*new_parent_dn = NULL;	/* np_dn, p_dn, or NULL */
77
	/* Used to interface with ldbm_modify_internal() */
78
	Modifications	*mod = NULL;		/* Used to delete old/add new rdn */
79
	int		manageDSAit = get_manageDSAit( op );
Juan Gomez's avatar
Juan Gomez committed
80

Gary Williams's avatar
Gary Williams committed
81
82
#ifdef NEW_LOGGING
	LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY,
83
		"ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
84
		dn->bv_len ? dn->bv_val : "NULL",
85
86
		( newSuperior && newSuperior->bv_len )
			? newSuperior->bv_val : "NULL" ));
Gary Williams's avatar
Gary Williams committed
87
#else
88
89
90
	Debug( LDAP_DEBUG_TRACE,
		"==>ldbm_back_modrdn: dn: %s newSuperior=%s\n", 
		dn->bv_len ? dn->bv_val : "NULL",
91
92
		( newSuperior && newSuperior->bv_len )
			? newSuperior->bv_val : "NULL", 0 );
Gary Williams's avatar
Gary Williams committed
93
94
#endif

95
	/* get entry with writer lock */
96
	if ( (e = dn2entry_w( be, ndn->bv_val, &matched )) == NULL ) {
97
		char* matched_dn = NULL;
98
		struct berval** refs;
99
100
101
102

		if( matched != NULL ) {
			matched_dn = strdup( matched->e_dn );
			refs = is_entry_referral( matched )
103
				? get_entry_referrals( be, conn, op, matched )
104
105
106
				: NULL;
			cache_return_entry_r( &li->li_cache, matched );
		} else {
107
			refs = referral_rewrite( default_referral,
108
				NULL, dn, LDAP_SCOPE_DEFAULT );
109
110
111
112
113
		}

		send_ldap_result( conn, op, LDAP_REFERRAL,
			matched_dn, NULL, refs, NULL );

114
115
		ber_bvecfree( refs );
		free( matched_dn );
116

Kurt Zeilenga's avatar
Kurt Zeilenga committed
117
118
119
		return( -1 );
	}

120
121
122
123
	if (!manageDSAit && is_entry_referral( e ) ) {
		/* parent is a referral, don't allow add */
		/* parent is an alias, don't allow add */
		struct berval **refs = get_entry_referrals( be,
124
			conn, op, e );
125

Gary Williams's avatar
Gary Williams committed
126
127
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
128
			"ldbm_back_modrdn: entry %s is a referral\n", e->e_dn ));
Gary Williams's avatar
Gary Williams committed
129
#else
130
		Debug( LDAP_DEBUG_TRACE, "entry %s is referral\n", e->e_dn,
131
		    0, 0 );
Gary Williams's avatar
Gary Williams committed
132
133
#endif

134
135
136
137
138
139
140
		send_ldap_result( conn, op, LDAP_REFERRAL,
		    e->e_dn, NULL, refs, NULL );

		ber_bvecfree( refs );
		goto return_results;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
141
142
143
	if ( has_children( be, e ) ) {
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
144
			"ldbm_back_modrdn: entry %s has children\n", e->e_dn ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
145
#else
146
		Debug( LDAP_DEBUG_TRACE, "entry %s has children\n", e->e_dn,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
147
148
149
150
151
152
153
154
		    0, 0 );
#endif

		send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
		    NULL, "subtree rename not supported", NULL, NULL );
		goto return_results;
	}

155
	p_ndn.bv_val = dn_parent( be, e->e_ndn );
Howard Chu's avatar
Howard Chu committed
156
157
158
159
	if ( p_ndn.bv_val )
		p_ndn.bv_len = e->e_nname.bv_len - (p_ndn.bv_val - e->e_ndn);
	else
		p_ndn.bv_len = 0;
160
161

	if ( p_ndn.bv_len != 0 ) {
162
		/* Make sure parent entry exist and we can write its 
Juan Gomez's avatar
Juan Gomez committed
163
164
165
		 * children.
		 */

166
		if( (p = dn2entry_w( be, p_ndn.bv_val, NULL )) == NULL) {
Gary Williams's avatar
Gary Williams committed
167
168
#ifdef NEW_LOGGING
			LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
169
				"ldbm_back_modrdn: parent of %s does not exist\n", e->e_ndn ));
Gary Williams's avatar
Gary Williams committed
170
#else
171
172
			Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
				0, 0, 0);
Gary Williams's avatar
Gary Williams committed
173
174
#endif

175
			send_ldap_result( conn, op, LDAP_OTHER,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
176
				NULL, "parent entry does not exist", NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
177

178
179
180
181
			goto return_results;
		}

		/* check parent for "children" acl */
182
		if ( ! access_allowed( be, conn, op, p,
183
			children, NULL, ACL_WRITE ) )
184
		{
Gary Williams's avatar
Gary Williams committed
185
186
187
188
#ifdef NEW_LOGGING
			LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
				   "ldbm_back_modrdn: no access to parent of (%s)\n", e->e_dn ));
#else
189
190
			Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
				0, 0 );
Gary Williams's avatar
Gary Williams committed
191
192
#endif

193
			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
194
				NULL, NULL, NULL, NULL );
195
196
197
			goto return_results;
		}

Gary Williams's avatar
Gary Williams committed
198
199
200
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
			   "ldbm_back_modrdn: wr to children of entry %s OK\n",
201
			   p_ndn.bv_val ));
Gary Williams's avatar
Gary Williams committed
202
#else
Juan Gomez's avatar
Juan Gomez committed
203
204
		Debug( LDAP_DEBUG_TRACE,
		       "ldbm_back_modrdn: wr to children of entry %s OK\n",
205
		       p_ndn.bv_val, 0, 0 );
Gary Williams's avatar
Gary Williams committed
206
207
#endif

208
		p_dn.bv_val = dn_parent( be, e->e_dn );
Howard Chu's avatar
Howard Chu committed
209
210
211
212
		if ( p_dn.bv_val )
			p_dn.bv_len = e->e_name.bv_len - (p_dn.bv_val - e->e_dn);
		else
			p_dn.bv_len = 0;
Juan Gomez's avatar
Juan Gomez committed
213

Gary Williams's avatar
Gary Williams committed
214
215
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
216
			   "ldbm_back_modrdn: parent dn=%s\n", p_dn.bv_val ));
Gary Williams's avatar
Gary Williams committed
217
#else
Juan Gomez's avatar
Juan Gomez committed
218
		Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
219
		       p_dn.bv_val, 0, 0 );
Gary Williams's avatar
Gary Williams committed
220
221
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
222
	} else {
223
		/* no parent, must be root to modify rdn */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
224
225
		isroot = be_isroot( be, &op->o_ndn );
		if ( ! isroot ) {
226
			if ( be_issuffix( be, "" ) || be_isupdate( be, &op->o_ndn ) ) {
227
				p = (Entry *)&slap_entry_root;
228
229
230
231
232
233
234
				
				rc = access_allowed( be, conn, op, p,
						children, NULL, ACL_WRITE );
				p = NULL;
								
				/* check parent for "children" acl */
				if ( ! rc ) {
Gary Williams's avatar
Gary Williams committed
235
#ifdef NEW_LOGGING
236
237
					LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
						"ldbm_back_modrdn: no access "
238
						"to parent \"\"\n" ));
Gary Williams's avatar
Gary Williams committed
239
#else
240
241
242
					Debug( LDAP_DEBUG_TRACE,
						"<=- ldbm_back_modrdn: no "
						"access to parent\n", 0, 0, 0 );
Gary Williams's avatar
Gary Williams committed
243
244
#endif

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
					send_ldap_result( conn, op, 
						LDAP_INSUFFICIENT_ACCESS,
						NULL, NULL, NULL, NULL );
					goto return_results;
				}

			} else {
#ifdef NEW_LOGGING
				LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
					   "ldbm_back_modrdn: (%s) has no "
					   "parent & not a root.\n", dn ));
#else
				Debug( LDAP_DEBUG_TRACE,
					"<=- ldbm_back_modrdn: no parent & "
					"not root\n", 0, 0, 0);
#endif

				send_ldap_result( conn, op, 
					LDAP_INSUFFICIENT_ACCESS,
					NULL, NULL, NULL, NULL );
				goto return_results;
			}
267
268
		}

269
		ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
270
		rootlock = 1;
Juan Gomez's avatar
Juan Gomez committed
271
		
Gary Williams's avatar
Gary Williams committed
272
273
274
275
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
			   "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn ));
#else
Juan Gomez's avatar
Juan Gomez committed
276
277
278
		Debug( LDAP_DEBUG_TRACE,
		       "ldbm_back_modrdn: no parent, locked root\n",
		       0, 0, 0 );
Gary Williams's avatar
Gary Williams committed
279
#endif
280
	}
Juan Gomez's avatar
Juan Gomez committed
281

282
	new_parent_dn = &p_dn;	/* New Parent unless newSuperior given */
Juan Gomez's avatar
Juan Gomez committed
283

Howard Chu's avatar
Howard Chu committed
284
	if ( newSuperior->bv_val != NULL ) {
Gary Williams's avatar
Gary Williams committed
285
286
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
287
288
			"ldbm_back_modrdn: new parent \"%s\" requested\n",
			newSuperior->bv_val ));
Gary Williams's avatar
Gary Williams committed
289
#else
Juan Gomez's avatar
Juan Gomez committed
290
		Debug( LDAP_DEBUG_TRACE, 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
291
			"ldbm_back_modrdn: new parent \"%s\" requested...\n",
292
			newSuperior->bv_val, 0, 0 );
Gary Williams's avatar
Gary Williams committed
293
294
#endif

295
296
		np_dn = newSuperior;
		np_ndn = nnewSuperior;
Juan Gomez's avatar
Juan Gomez committed
297

298
		/* newSuperior == oldParent? */
299
300
		if ( p_ndn.bv_len == np_ndn->bv_len &&
			strcmp( p_ndn.bv_val, np_ndn->bv_val ) == 0 ) {
Gary Williams's avatar
Gary Williams committed
301
#ifdef NEW_LOGGING
302
303
304
			LDAP_LOG(( "backend", LDAP_LEVEL_INFO, "ldbm_back_modrdn: "
				"new parent\"%s\" seems to be the same as the "
				"old parent \"%s\"\n",
305
				newSuperior->bv_val, p_dn.bv_val ));
Gary Williams's avatar
Gary Williams committed
306
#else
307
308
309
			Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: "
				"new parent\"%s\" seems to be the same as the "
				"old parent \"%s\"\n",
310
				newSuperior->bv_val, p_dn.bv_val, 0 );
Gary Williams's avatar
Gary Williams committed
311
312
#endif

313
314
315
316
			newSuperior = NULL; /* ignore newSuperior */
		}
	}

Howard Chu's avatar
Howard Chu committed
317
	if ( newSuperior && newSuperior->bv_val != NULL ) {
Juan Gomez's avatar
Juan Gomez committed
318
319
320
		/* newSuperior == entry being moved?, if so ==> ERROR */
		/* Get Entry with dn=newSuperior. Does newSuperior exist? */

321
		if ( nnewSuperior->bv_len ) {
322
			if( (np = dn2entry_w( be, np_ndn->bv_val, NULL )) == NULL) {
Gary Williams's avatar
Gary Williams committed
323
#ifdef NEW_LOGGING
324
				LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
325
					"ldbm_back_modrdn: newSup(ndn=%s) not found.\n", np_ndn->bv_val ));
Gary Williams's avatar
Gary Williams committed
326
#else
327
				Debug( LDAP_DEBUG_TRACE,
328
				    "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
329
				    np_ndn->bv_val, 0, 0);
Gary Williams's avatar
Gary Williams committed
330
331
#endif

332
333
334
335
				send_ldap_result( conn, op, LDAP_OTHER,
					NULL, "newSuperior not found", NULL, NULL );
				goto return_results;
			}
Juan Gomez's avatar
Juan Gomez committed
336

Gary Williams's avatar
Gary Williams committed
337
#ifdef NEW_LOGGING
338
			LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
339
340
				"ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
				np, np->e_id ));
Gary Williams's avatar
Gary Williams committed
341
#else
342
			Debug( LDAP_DEBUG_TRACE,
343
344
				"ldbm_back_modrdn: wr to new parent OK np=%p, id=%ld\n",
				np, np->e_id, 0 );
Gary Williams's avatar
Gary Williams committed
345
346
#endif

347
348
349
350
			/* check newSuperior for "children" acl */
			if ( !access_allowed( be, conn, op, np, children, NULL,
					      ACL_WRITE ) )
			{
Gary Williams's avatar
Gary Williams committed
351
#ifdef NEW_LOGGING
352
353
				LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
					   "ldbm_back_modrdn: no wr to newSup children.\n" ));
Gary Williams's avatar
Gary Williams committed
354
#else
355
356
357
				Debug( LDAP_DEBUG_TRACE,
				       "ldbm_back_modrdn: no wr to newSup children\n",
				       0, 0, 0 );
Gary Williams's avatar
Gary Williams committed
358
359
#endif

360
361
362
363
				send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
					NULL, NULL, NULL, NULL );
				goto return_results;
			}
364

365
366
			if ( is_entry_alias( np ) ) {
				/* parent is an alias, don't allow add */
Gary Williams's avatar
Gary Williams committed
367
#ifdef NEW_LOGGING
368
369
				LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
					   "ldbm_back_modrdn: entry (%s) is an alias.\n", np->e_dn ));
Gary Williams's avatar
Gary Williams committed
370
#else
371
				Debug( LDAP_DEBUG_TRACE, "entry is alias\n", 0, 0, 0 );
Gary Williams's avatar
Gary Williams committed
372
373
#endif

374

375
376
				send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
				    NULL, "newSuperior is an alias", NULL, NULL );
377

378
379
				goto return_results;
			}
380

381
382
			if ( is_entry_referral( np ) ) {
				/* parent is a referral, don't allow add */
Gary Williams's avatar
Gary Williams committed
383
#ifdef NEW_LOGGING
384
385
				LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
					"ldbm_back_modrdn: entry (%s) is a referral\n",
386
				np->e_dn ));
Gary Williams's avatar
Gary Williams committed
387
#else
388
389
				Debug( LDAP_DEBUG_TRACE, "entry (%s) is referral\n",
					np->e_dn, 0, 0 );
Gary Williams's avatar
Gary Williams committed
390
391
#endif

392
393
				send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
				    NULL, "newSuperior is a referral", NULL, NULL );
394

395
396
397
398
399
400
401
				goto return_results;
			}

		} else {

			/* no parent, must be root to modify newSuperior */
			if ( isroot == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
402
				isroot = be_isroot( be, &op->o_ndn );
403
404
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
405
			if ( ! isroot ) {
406
				if ( be_issuffix( be, "" ) || be_isupdate( be, &op->o_ndn ) ) {
407
					np = (Entry *)&slap_entry_root;
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
				
					rc = access_allowed( be, conn, op, np,
							children, NULL, ACL_WRITE );
					np = NULL;
								
					/* check parent for "children" acl */
					if ( ! rc ) {
#ifdef NEW_LOGGING
						LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
							"ldbm_back_modrdn: no access "
							"to new superior \"\"\n" ));
#else
						Debug( LDAP_DEBUG_TRACE,
							"<=- ldbm_back_modrdn: no "
							"access to new superior\n", 0, 0, 0 );
#endif

						send_ldap_result( conn, op, 
							LDAP_INSUFFICIENT_ACCESS,
							NULL, NULL, NULL, NULL );
						goto return_results;
					}

				} else {
#ifdef NEW_LOGGING
					LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
						   "ldbm_back_modrdn: \"\" "
						   "not allowed as new superior\n" ));
#else
					Debug( LDAP_DEBUG_TRACE,
						"<=- ldbm_back_modrdn: \"\" "
						"not allowed as new superior\n", 
						0, 0, 0);
#endif

					send_ldap_result( conn, op, 
						LDAP_INSUFFICIENT_ACCESS,
						NULL, NULL, NULL, NULL );
					goto return_results;
				}
			}
Juan Gomez's avatar
Juan Gomez committed
449
450
		}

Gary Williams's avatar
Gary Williams committed
451
452
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
453
			"ldbm_back_modrdn: wr to new parent's children OK.\n" ));
Gary Williams's avatar
Gary Williams committed
454
#else
Juan Gomez's avatar
Juan Gomez committed
455
		Debug( LDAP_DEBUG_TRACE,
456
457
		    "ldbm_back_modrdn: wr to new parent's children OK\n",
		    0, 0, 0 );
Gary Williams's avatar
Gary Williams committed
458
459
#endif

Juan Gomez's avatar
Juan Gomez committed
460
		new_parent_dn = np_dn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
	}
Juan Gomez's avatar
Juan Gomez committed
462
463
	
	/* Build target dn and make sure target entry doesn't exist already. */
464
465
	build_new_dn( &new_dn, new_parent_dn, newrdn ); 
	dnNormalize( NULL, &new_dn, &new_ndn );
Juan Gomez's avatar
Juan Gomez committed
466

Gary Williams's avatar
Gary Williams committed
467
468
#ifdef NEW_LOGGING
	LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
469
		"ldbm_back_modrdn: new ndn=%s\n", new_ndn->bv_val ));
Gary Williams's avatar
Gary Williams committed
470
#else
Juan Gomez's avatar
Juan Gomez committed
471
	Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
472
	    new_ndn->bv_val, 0, 0 );
Gary Williams's avatar
Gary Williams committed
473
474
#endif

475
476
477
478
479
480
481
482
	/* check for abandon */
	ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
	if ( op->o_abandon ) {
		ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
		goto return_results;
	}

	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
483
	if ( ( rc_id = dn2id ( be, new_ndn->bv_val, &id ) ) || id != NOID ) {
484
485
486
		/* if (rc_id) something bad happened to ldbm cache */
		send_ldap_result( conn, op, 
			rc_id ? LDAP_OPERATIONS_ERROR : LDAP_ALREADY_EXISTS,
487
			NULL, NULL, NULL, NULL );
488
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
489
490
	}

Gary Williams's avatar
Gary Williams committed
491
492
#ifdef NEW_LOGGING
	LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
493
		"ldbm_back_modrdn: new ndn (%s) does not exist\n", new_ndn ));
Gary Williams's avatar
Gary Williams committed
494
#else
Juan Gomez's avatar
Juan Gomez committed
495
	Debug( LDAP_DEBUG_TRACE,
496
497
	    "ldbm_back_modrdn: new ndn=%s does not exist\n",
	    new_ndn, 0, 0 );
Gary Williams's avatar
Gary Williams committed
498
499
#endif

500
501
502
503

	/* Get attribute types and values of our new rdn, we will
	 * need to add that to our new entry
	 */
504
	if ( rdn_attrs( newrdn->bv_val, &new_rdn_types, &new_rdn_vals ) ) {
505
506
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
507
			"ldbm_back_modrdn: can't figure out type(s)/value(s) of newrdn\n" ));
508
509
#else
		Debug( LDAP_DEBUG_TRACE,
510
511
		    "ldbm_back_modrdn: can't figure out type(s)/value(s) of newrdn\n",
		    0, 0, 0 );
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
#endif

		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			NULL, "unable to parse type(s)/value(s) used in RDN", NULL, NULL );
		goto return_results;		
	}

#ifdef NEW_LOGGING
	LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
		   "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
		   new_rdn_vals[0], new_rdn_types[0] ));
#else
	Debug( LDAP_DEBUG_TRACE,
	       "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
	       new_rdn_vals[0], new_rdn_types[0], 0 );
#endif

	/* Retrieve the old rdn from the entry's dn */
530
	if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
531
532
533
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
			   "ldbm_back_modrdn: can't figure out old_rdn from dn (%s)\n",
534
			   dn->bv_val ));
535
536
537
538
539
540
541
542
543
544
545
#else
		Debug( LDAP_DEBUG_TRACE,
		       "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
		       0, 0, 0 );
#endif

		send_ldap_result( conn, op, LDAP_OTHER,
			NULL, "could not parse old DN", NULL, NULL );
		goto return_results;		
	}

546
	if ( rdn_attrs( old_rdn, &old_rdn_types, &old_rdn_vals ) ) {
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
#ifdef NEW_LOGGING
		LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
			   "ldbm_back_modrdn: can't figure out the old_rdn type(s)/value(s).\n" ));
#else
		Debug( LDAP_DEBUG_TRACE,
		       "ldbm_back_modrdn: can't figure out the old_rdn type(s)/value(s)\n",
		       0, 0, 0 );
#endif

		send_ldap_result( conn, op, LDAP_OTHER,
			NULL, "unable to parse type(s)/value(s) used in RDN from old DN", NULL, NULL );
		goto return_results;		
	}
	
	if ( newSuperior == NULL
		&& charray_strcasecmp( (const char **)old_rdn_types, (const char **)new_rdn_types ) != 0 )
	{
	    /* Not a big deal but we may say something */
#ifdef NEW_LOGGING
	    LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
		       "ldbm_back_modrdn: old_rdn_type=%s new_rdn_type=%s\n",
		       old_rdn_types[0], new_rdn_types[0] ));
#else
	    Debug( LDAP_DEBUG_TRACE,
		   "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
		   old_rdn_types[0], new_rdn_types[0], 0 );
#endif
	}		

#ifdef NEW_LOGGING
	LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
		   "ldbm_back_modrdn:  DN_X500\n" ));
#else
	Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
	       0, 0, 0 );
#endif

	mod = NULL;
	for ( a_cnt = 0; new_rdn_types[a_cnt]; a_cnt++ ) {
586
587
588
589
		int 			rc;
		AttributeDescription	*desc = NULL;
		Modifications 		*mod_tmp;
		struct berval 		val;
590
591


592
		rc = slap_str2ad( new_rdn_types[a_cnt], &desc, &text );
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610

		if ( rc != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
			LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
				   "ldbm_back_modrdn: slap_str2ad error: %s (%s)\n",
				   text, new_rdn_types[a_cnt] ));
#else
			Debug( LDAP_DEBUG_TRACE,
				"ldbm_back_modrdn: %s: %s (new)\n",
				text, new_rdn_types[a_cnt], 0 );
#endif

			send_ldap_result( conn, op, rc,
				NULL, text, NULL, NULL );

			goto return_results;		
		}

611
612
		val.bv_val = new_rdn_vals[a_cnt];
		val.bv_len = strlen( val.bv_val );
613
		if ( ! access_allowed( be, conn, op, e, 
614
				desc, &val, ACL_WRITE ) ) {
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
#ifdef NEW_LOGGING
			LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
				   "ldbm_back_modrdn: access "
				   "not allowed to attr \"%s\"\n",
				   new_rdn_types[a_cnt] ));
#else
			Debug( LDAP_DEBUG_TRACE,
				"ldbm_back_modrdn: access not allowed "
				"to attr \"%s\"\n%s%s",
				new_rdn_types[a_cnt], "", "" );
#endif
			send_ldap_result( conn, op, 
				LDAP_INSUFFICIENT_ACCESS,
				NULL, NULL, NULL, NULL );

			goto return_results;
		}

633
634
		mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) );
		mod_tmp->sml_desc = desc;
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
		mod_tmp->sml_bvalues = (struct berval **)ch_malloc( 2 * sizeof(struct berval *) );
		mod_tmp->sml_bvalues[0] = ber_bvstrdup( new_rdn_vals[a_cnt] );
		mod_tmp->sml_bvalues[1] = NULL;
		mod_tmp->sml_op = SLAP_MOD_SOFTADD;
		mod_tmp->sml_next = mod;
		mod = mod_tmp;
	}

	/* Remove old rdn value if required */
	if ( deleteoldrdn ) {
		/* Get value of old rdn */
		if ( old_rdn_vals == NULL ) {
#ifdef NEW_LOGGING
			LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
				   "ldbm_back_modrdn: can't figure out old RDN value(s) from old RDN\n" ));
#else
			Debug( LDAP_DEBUG_TRACE,
			       "ldbm_back_modrdn: can't figure out oldRDN value(s) from old RDN\n",
			       0, 0, 0 );
#endif

			send_ldap_result( conn, op, LDAP_OTHER,
				NULL, "could not parse value(s) from old RDN", NULL, NULL );
			goto return_results;		
		}

		for ( d_cnt = 0; old_rdn_types[d_cnt]; d_cnt++ ) {    
662
663
664
665
			int 			rc;
			AttributeDescription	*desc = NULL;
			Modifications 		*mod_tmp;
			struct berval 		val;
666
667


668
			rc = slap_str2ad( old_rdn_types[d_cnt], &desc, &text );
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686

			if ( rc != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
				LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
					   "ldbm_back_modrdn: %s: %s (old)\n",
					   text, old_rdn_types[d_cnt] ));
#else
				Debug( LDAP_DEBUG_TRACE,
					"ldbm_back_modrdn: %s: %s (old)\n",
					text, old_rdn_types[d_cnt], 0 );
#endif

				send_ldap_result( conn, op, rc,
					NULL, text, NULL, NULL );

				goto return_results;
			}

687
			val.bv_val = old_rdn_vals[d_cnt];
688
			val.bv_len = strlen( val.bv_val );
689
			if ( ! access_allowed( be, conn, op, e, 
690
					desc, &val, ACL_WRITE ) ) {
691
692
693
694
#ifdef NEW_LOGGING
				LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
					   "ldbm_back_modrdn: access "
					   "not allowed to attr \"%s\"\n",
695
					   old_rdn_types[d_cnt] ));
696
697
698
699
#else
				Debug( LDAP_DEBUG_TRACE,
					"ldbm_back_modrdn: access not allowed "
					"to attr \"%s\"\n%s%s",
700
					old_rdn_types[d_cnt], "", "" );
701
702
703
704
705
706
707
708
#endif
				send_ldap_result( conn, op, 
					LDAP_INSUFFICIENT_ACCESS,
					NULL, NULL, NULL, NULL );

				goto return_results;
			}

709
			/* Remove old value of rdn as an attribute. */
710
711
			mod_tmp = (Modifications *)ch_malloc( sizeof( Modifications ) );
			mod_tmp->sml_desc = desc;
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
			mod_tmp->sml_bvalues = (struct berval **)ch_malloc( 2 * sizeof(struct berval *) );
			mod_tmp->sml_bvalues[0] = ber_bvstrdup( old_rdn_vals[d_cnt] );
			mod_tmp->sml_bvalues[1] = NULL;
			mod_tmp->sml_op = LDAP_MOD_DELETE;
			mod_tmp->sml_next = mod;
			mod = mod_tmp;

#ifdef NEW_LOGGING
			LDAP_LOG(( "backend", LDAP_LEVEL_DETAIL1,
				   "ldbm_back_modrdn: removing old_rdn_val=%s\n", old_rdn_vals[0] ));
#else
			Debug( LDAP_DEBUG_TRACE,
			       "ldbm_back_modrdn: removing old_rdn_val=%s\n",
			       old_rdn_vals[0], 0, 0 );
#endif
		}
	}

730
	
731
732
733
734
735
736
737
738
	/* check for abandon */
	ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
	if ( op->o_abandon ) {
		ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
		goto return_results;
	}
	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );

739
740
	/* delete old one */
	if ( dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
741
		send_ldap_result( conn, op, LDAP_OTHER,
742
			NULL, "DN index delete fail", NULL, NULL );
743
744
745
746
		goto return_results;
	}

	(void) cache_delete_entry( &li->li_cache, e );
747
	rc = MUST_DESTROY;
748
749
750

	/* XXX: there is no going back! */

751
752
	free( e->e_dn );
	free( e->e_ndn );
753
754
755
	e->e_name = new_dn;
	e->e_nname = *new_ndn;
	new_dn.bv_val = NULL;
756
	new_ndn = NULL;
757
758
759

	/* add new one */
	if ( dn2id_add( be, e->e_ndn, e->e_id ) != 0 ) {
760
		send_ldap_result( conn, op, LDAP_OTHER,
761
			NULL, "DN index add failed", NULL, NULL );
762
763
764
		goto return_results;
	}

765
	/* modify memory copy of entry */
766
	rc = ldbm_modify_internal( be, conn, op, dn->bv_val, &mod[0], e,
767
		&text, textbuf, textlen );
768
769
770
771

	if( rc != LDAP_SUCCESS ) {
		if( rc != SLAPD_ABANDON ) {
			send_ldap_result( conn, op, rc,
772
				NULL, text, NULL, NULL );
773
		}
774
775
776
777
778
779

		/* here we may try to delete the newly added dn */
		if ( dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
			/* we already are in trouble ... */
			;
		}
780
	    
781
    		goto return_results;
782
783
	}
	
784
785
	(void) cache_update_entry( &li->li_cache, e );

786
787
788
789
	/* NOTE: after this you must not free new_dn or new_ndn!
	 * They are used by cache.
	 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
790
791
	/* id2entry index */
	if ( id2entry_add( be, e ) != 0 ) {
792
		send_ldap_result( conn, op, LDAP_OTHER,
793
			NULL, "entry update failed", NULL, NULL );
794
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
795
	}
796

797
798
	send_ldap_result( conn, op, LDAP_SUCCESS,
		NULL, NULL, NULL, NULL );
799
	rc = 0;
800
	cache_entry_commit( e );
801
802

return_results:
803
804
	if( new_dn.bv_val != NULL ) free( new_dn.bv_val );
	if( new_ndn != NULL ) ber_bvfree( new_ndn );
805

806
	/* LDAP v2 supporting correct attribute handling. */
807
808
	if( new_rdn_types != NULL ) charray_free( new_rdn_types );
	if( new_rdn_vals != NULL ) charray_free( new_rdn_vals );
809
	if( old_rdn != NULL ) free(old_rdn);
810
811
812
813
814
815
	if( old_rdn_types != NULL ) charray_free( old_rdn_types );
	if( old_rdn_vals != NULL ) charray_free( old_rdn_vals );

	if ( mod != NULL ) {
		slap_mods_free( mod );
	}
816

Juan Gomez's avatar
Juan Gomez committed
817
	/* LDAP v3 Support */
818
819
820
821
822
	if( np != NULL ) {
		/* free new parent and writer lock */
		cache_return_entry_w( &li->li_cache, np );
	}

823
824
825
	if( p != NULL ) {
		/* free parent and writer lock */
		cache_return_entry_w( &li->li_cache, p );
826
	}
827

828
	if ( rootlock ) {
829
		/* release root writer lock */
830
		ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
831
	}
832
833
834

	/* free entry and writer lock */
	cache_return_entry_w( &li->li_cache, e );
835
836
837
838
	if ( rc == MUST_DESTROY ) {
		/* if rc == MUST_DESTROY the entry is uncached 
		 * and its private data is destroyed; 
		 * the entry must be freed */
839
840
		entry_free( e );
	}
841
	return( rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
842
}