modrdn.c 11.4 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
5
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
/*
 * Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
 */

18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * LDAP v3 newSuperior support.
 *
 * 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
31
32
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
33
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
36
37

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

38
#include "ldap_pvt.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
40
#include "slap.h"

41
int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
43
44
45
46
do_modrdn(
    Connection	*conn,
    Operation	*op
)
{
47
48
49
	struct berval dn = { 0, NULL };
	struct berval newrdn = { 0, NULL };
	struct berval newSuperior = { 0, NULL };
50
	ber_int_t	deloldrdn;
51

52
53
54
55
56
57
58
	struct berval *pdn = NULL;
	struct berval *pnewrdn = NULL;
	struct berval *pnewSuperior = NULL;

	struct berval *ndn = NULL;
	struct berval *nnewrdn = NULL;
	struct berval *nnewSuperior = NULL;
59
60

	Backend	*be;
61
	Backend	*newSuperior_be = NULL;
62
	ber_len_t	length;
63
	int rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
64
	const char *text;
65
	int manageDSAit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
66

67
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
68
	LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
69
		"do_modrdn: begin\n" ));
70
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
71
	Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
72
73
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
74
75
76
77
78
79
80

	/*
	 * Parse the modrdn request.  It looks like this:
	 *
	 *	ModifyRDNRequest := SEQUENCE {
	 *		entry	DistinguishedName,
	 *		newrdn	RelativeDistinguishedName
81
82
	 *		deleteoldrdn	BOOLEAN,
	 *		newSuperior	[0] LDAPDN OPTIONAL (v3 Only!)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
83
84
85
	 *	}
	 */

86
87
88
	if ( ber_scanf( op->o_ber, "{oob", &dn, &newrdn, &deloldrdn )
	    == LBER_ERROR )
	{
89
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
90
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
91
			"do_modrdn: ber_scanf failed\n" ));
92
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
		Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
94
95
#endif

96
97
		send_ldap_disconnect( conn, op,
			LDAP_PROTOCOL_ERROR, "decoding error" );
98
		return SLAPD_DISCONNECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
99
100
	}

101
102
103
	/* Check for newSuperior parameter, if present scan it */

	if ( ber_peek_tag( op->o_ber, &length ) == LDAP_TAG_NEWSUPERIOR ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
104
		if ( op->o_protocol < LDAP_VERSION3 ) {
105
106
107
			/* Conection record indicates v2 but field 
			 * newSuperior is present: report error.
			 */
108
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
109
			LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
110
				"do_modrdn: (v2) invalid field newSuperior.\n" ));
111
#else
112
			Debug( LDAP_DEBUG_ANY,
113
114
			    "modrdn(v2): invalid field newSuperior!\n",
			    0, 0, 0 );
115
116
#endif

117
118
			send_ldap_disconnect( conn, op,
				LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
119
			rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
120
			goto cleanup;
121
		}
122

123
		if ( ber_scanf( op->o_ber, "o", &newSuperior ) 
124
125
		     == LBER_ERROR ) {

126
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
127
			LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
128
				"do_modrdn: ber_scanf(\"a\") failed\n" ));
129
#else
Howard Chu's avatar
Howard Chu committed
130
			Debug( LDAP_DEBUG_ANY, "ber_scanf(\"a\") failed\n",
131
				0, 0, 0 );
132
133
#endif

134
135
			send_ldap_disconnect( conn, op,
				LDAP_PROTOCOL_ERROR, "decoding error" );
136
			rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
137
			goto cleanup;
138
		}
139
	}
140

141
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
142
	LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
143
144
145
		"do_modrdn: dn (%s) newrdn (%s) newsuperior(%s)\n",
		dn.bv_val, newrdn.bv_val,
		newSuperior.bv_len ? newSuperior.bv_val : "" ));
146
#else
147
148
	Debug( LDAP_DEBUG_ARGS,
	    "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
149
150
		dn.bv_val, newrdn.bv_val,
		newSuperior.bv_len ? newSuperior.bv_val : "" );
151
152
#endif

153
	if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
154
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
155
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
156
			"do_modrdn: ber_scanf failed\n" ));
157
#else
158
		Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
159
160
#endif

161
		send_ldap_disconnect( conn, op,
162
			LDAP_PROTOCOL_ERROR, "decoding error" );
163
		rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
164
		goto cleanup;
165
166
	}

167
	if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
168
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
169
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
170
			"do_modrdn: get_ctrls failed\n" ));
171
#else
172
		Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 );
173
174
#endif

Gary Williams's avatar
Gary Williams committed
175
		/* get_ctrls has sent results.	Now clean up. */
Howard Chu's avatar
Howard Chu committed
176
		goto cleanup;
177
178
	} 

179
	rc = dnPretty( NULL, &dn, &pdn );
180
	if( rc != LDAP_SUCCESS ) {
181
#ifdef NEW_LOGGING
182
183
184
		LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
			"do_modrdn: conn %d  invalid dn (%s)\n",
			conn->c_connid, dn.bv_val ));
185
#else
186
187
		Debug( LDAP_DEBUG_ANY,
			"do_modrdn: invalid dn (%s)\n", dn.bv_val, 0, 0 );
188
#endif
189
190
191
192
193
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid DN", NULL, NULL );
		goto cleanup;
	}

194
195
	rc = dnNormalize( NULL, &dn, &ndn );
	if( rc != LDAP_SUCCESS ) {
196
#ifdef NEW_LOGGING
197
198
199
		LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
			"do_modrdn: conn %d  invalid dn (%s)\n",
			conn->c_connid, pdn->bv_val ));
200
#else
201
202
		Debug( LDAP_DEBUG_ANY,
			"do_modrdn: invalid dn (%s)\n", pdn->bv_val, 0, 0 );
203
#endif
204
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
205
		    "invalid DN", NULL, NULL );
206
207
208
		goto cleanup;
	}

209
	if( ndn->bv_len == 0 ) {
210
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
211
212
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn:  attempt to modify root DSE.\n" ));
213
#else
214
		Debug( LDAP_DEBUG_ANY, "do_modrdn: root dse!\n", 0, 0, 0 );
215
216
#endif

217
218
219
		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
			NULL, "cannot rename the root DSE", NULL, NULL );
		goto cleanup;
220
221

#ifdef SLAPD_SCHEMA_DN
222
	} else if ( strcasecmp( ndn->bv_val, SLAPD_SCHEMA_DN ) == 0 ) {
223
224
225
226
227
228
229
230
231
232
233
#ifdef NEW_LOGGING
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			"do_modrdn: attempt to modify subschema subentry\n" ));
#else
		Debug( LDAP_DEBUG_ANY, "do_modrdn: subschema subentry!\n", 0, 0, 0 );
#endif

		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
			NULL, "cannot rename subschema subentry", NULL, NULL );
		goto cleanup;
#endif
234
235
	}

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
	/* FIXME: should have/use rdnPretty / rdnNormalize routines */

	rc = dnPretty( NULL, &newrdn, &pnewrdn );
	if( rc != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
		LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
			"do_modrdn: conn %d  invalid newrdn (%s)\n",
			conn->c_connid, newrdn.bv_val ));
#else
		Debug( LDAP_DEBUG_ANY,
			"do_modrdn: invalid newrdn (%s)\n", newrdn.bv_val, 0, 0 );
#endif
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid new RDN", NULL, NULL );
		goto cleanup;
	}

	rc = dnNormalize( NULL, &newrdn, &nnewrdn );
	if( rc != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
		LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
			"do_modrdn: conn %d  invalid newrdn (%s)\n",
			conn->c_connid, pnewrdn->bv_val ));
#else
		Debug( LDAP_DEBUG_ANY,
			"do_modrdn: invalid newrdn (%s)\n", pnewrdn->bv_val, 0, 0 );
#endif
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid new RDN", NULL, NULL );
		goto cleanup;
	}

Pierangelo Masarati's avatar
:)    
Pierangelo Masarati committed
268
	if( rdnValidate( pnewrdn ) != LDAP_SUCCESS ) {
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
#ifdef NEW_LOGGING
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			"do_modrdn: invalid rdn (%s).\n", pnewrdn->bv_val ));
#else
		Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid rdn (%s)\n",
			pnewrdn->bv_val, 0, 0 );
#endif

		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid new RDN", NULL, NULL );
		goto cleanup;
	}

	if( newSuperior.bv_len ) {
		rc = dnPretty( NULL, &newSuperior, &pnewSuperior );
		if( rc != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
			LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
				"do_modrdn: conn %d  invalid newSuperior (%s)\n",
				conn->c_connid, newSuperior.bv_val ));
#else
			Debug( LDAP_DEBUG_ANY,
				"do_modrdn: invalid newSuperior (%s)\n",
				newSuperior.bv_val, 0, 0 );
#endif
			send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
				"invalid newSuperior", NULL, NULL );
			goto cleanup;
		}

		rc = dnNormalize( NULL, &newSuperior, &nnewSuperior );
		if( rc != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
			LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
				"do_modrdn: conn %d  invalid newSuperior (%s)\n",
				conn->c_connid, pnewSuperior->bv_val ));
#else
			Debug( LDAP_DEBUG_ANY,
				"do_modrdn: invalid newSuperior (%s)\n",
				pnewSuperior->bv_val, 0, 0 );
#endif
			send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
				"invalid newSuperior", NULL, NULL );
			goto cleanup;
		}
	}

Hallvard Furuseth's avatar
Hallvard Furuseth committed
316
	Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d MODRDN dn=\"%s\"\n",
317
	    op->o_connid, op->o_opid, pdn->bv_val, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
318

319
320
	manageDSAit = get_manageDSAit( op );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
321
322
323
324
325
	/*
	 * We could be serving multiple database backends.  Select the
	 * appropriate one, or send a referral to our "referral server"
	 * if we don't hold it.
	 */
326
	if ( (be = select_backend( ndn, manageDSAit, 0 )) == NULL ) {
327
		struct berval **ref = referral_rewrite( default_referral,
328
			NULL, pdn, LDAP_SCOPE_DEFAULT );
329

330
		send_ldap_result( conn, op, rc = LDAP_REFERRAL,
331
332
333
			NULL, NULL, ref ? ref : default_referral, NULL );

		ber_bvecfree( ref );
Howard Chu's avatar
Howard Chu committed
334
		goto cleanup;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
335
336
	}

337
338
	/* check restrictions */
	rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
339
340
	if( rc != LDAP_SUCCESS ) {
		send_ldap_result( conn, op, rc,
341
			NULL, text, NULL, NULL );
342
		goto cleanup;
343
344
	}

345
	/* check for referrals */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
346
	rc = backend_check_referrals( be, conn, op, pdn, ndn );
347
348
349
350
	if ( rc != LDAP_SUCCESS ) {
		goto cleanup;
	}

351
352
353
	/* Make sure that the entry being changed and the newSuperior are in 
	 * the same backend, otherwise we return an error.
	 */
354
	if( newSuperior.bv_len ) {
355
		newSuperior_be = select_backend( nnewSuperior, 0, 0 );
356

357
		if ( newSuperior_be != be ) {
358
359
			/* newSuperior is in same backend */
			rc = LDAP_AFFECTS_MULTIPLE_DSAS;
360

361
			send_ldap_result( conn, op, rc,
362
				NULL, "cannot rename between DSAa", NULL, NULL );
363

Howard Chu's avatar
Howard Chu committed
364
			goto cleanup;
365
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
366
367
368

		/* deref suffix alias if appropriate */
		suffix_alias( be, nnewSuperior );
369
	}
370

Kurt Zeilenga's avatar
Kurt Zeilenga committed
371
	/* deref suffix alias if appropriate */
372
	suffix_alias( be, ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
373

Kurt Zeilenga's avatar
Kurt Zeilenga committed
374
375
376
377
	/*
	 * do the add if 1 && (2 || 3)
	 * 1) there is an add function implemented in this backend;
	 * 2) this backend is master for what it holds;
378
	 * 3) it's a replica and the dn supplied is the update_ndn.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
379
	 */
380
	if ( be->be_modrdn ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
381
		/* do the update here */
382
		int repl_user = be_isupdate( be, &op->o_ndn );
383
#ifndef SLAPD_MULTIMASTER
384
		if ( !be->be_update_ndn.bv_len || repl_user )
385
#endif
386
		{
387
388
389
			if ( (*be->be_modrdn)( be, conn, op, pdn, ndn,
				pnewrdn, nnewrdn, deloldrdn,
				pnewSuperior, nnewSuperior ) == 0
390
#ifdef SLAPD_MULTIMASTER
391
				&& ( !be->be_update_ndn.bv_len || !repl_user )
392
393
#endif
			) {
394
395
				struct slap_replog_moddn moddn;
				moddn.newrdn = pnewrdn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
396
				moddn.deloldrdn = deloldrdn;
397
				moddn.newsup = pnewSuperior;
398

399
				replog( be, op, pdn, ndn, &moddn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
400
			}
401
#ifndef SLAPD_MULTIMASTER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
402
		} else {
403
404
405
			struct berval **defref = be->be_update_refs
				? be->be_update_refs : default_referral;
			struct berval **ref = referral_rewrite( defref,
406
				NULL, pdn, LDAP_SCOPE_DEFAULT );
407

408
			send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
409
410
411
				ref ? ref : defref, NULL );

			ber_bvecfree( ref );
412
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
413
414
		}
	} else {
415
		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
416
417
			NULL, "operation not supported within namingContext",
			NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
418
419
	}

Howard Chu's avatar
Howard Chu committed
420
cleanup:
421
	free( dn.bv_val );
422
423
424
	if( pdn != NULL ) ber_bvfree( pdn );
	if( ndn != NULL ) ber_bvfree( ndn );

425
	free( newrdn.bv_val );	
426
427
	if( pnewrdn != NULL ) ber_bvfree( pnewrdn );
	if( nnewrdn != NULL ) ber_bvfree( nnewrdn );
428

429
	free( newSuperior.bv_val );
430
431
	if ( pnewSuperior != NULL ) ber_bvfree( pnewSuperior );
	if ( nnewSuperior != NULL ) ber_bvfree( nnewSuperior );
432

433
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
434
}