modrdn.c 8.34 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
)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
	char	*dn, *ndn = NULL, *newrdn;
48
	ber_int_t	deloldrdn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
49
	Backend	*be;
50
51
	/* Vars for LDAP v3 newSuperior support */
	char	*newSuperior = NULL;
Gary Williams's avatar
Gary Williams committed
52
	char	*nnewSuperior = NULL;
53
	Backend	*newSuperior_be = NULL;
54
	ber_len_t	length;
55
	int rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
	const char *text;
57
	int manageDSAit;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
58

59
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
60
61
	LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
		   "do_modrdn: begin\n" ));
62
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
63
	Debug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
64
65
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
66
67
68
69
70
71
72

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

78
	if ( ber_scanf( op->o_ber, "{aab", &dn, &newrdn, &deloldrdn )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
79
	    == LBER_ERROR ) {
80
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
81
82
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn: ber_scanf failed\n" ));
83
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
84
		Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
85
86
#endif

87
88
		send_ldap_disconnect( conn, op,
			LDAP_PROTOCOL_ERROR, "decoding error" );
89
		return SLAPD_DISCONNECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
91
	}

92
93
94
	/* 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
95
		if ( op->o_protocol < LDAP_VERSION3 ) {
96
97
98
			/* Conection record indicates v2 but field 
			 * newSuperior is present: report error.
			 */
99
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
100
101
			LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
				   "do_modrdn: (v2) invalid field newSuperior.\n" ));
102
#else
103
			Debug( LDAP_DEBUG_ANY,
104
			       "modrdn(v2): invalid field newSuperior!\n",
105
			       0, 0, 0 );
106
107
#endif

108
109
			send_ldap_disconnect( conn, op,
				LDAP_PROTOCOL_ERROR, "newSuperior requires LDAPv3" );
110
			rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
111
			goto cleanup;
112
		}
113

114
		if ( ber_scanf( op->o_ber, "a", &newSuperior ) 
115
116
		     == LBER_ERROR ) {

117
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
118
119
			LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
				   "do_modrdn: ber_scanf(\"a\") failed\n" ));
120
#else
Howard Chu's avatar
Howard Chu committed
121
			Debug( LDAP_DEBUG_ANY, "ber_scanf(\"a\") failed\n",
122
			   0, 0, 0 );
123
124
#endif

125
126
			send_ldap_disconnect( conn, op,
				LDAP_PROTOCOL_ERROR, "decoding error" );
127
			rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
128
			goto cleanup;
129
130
131
		}

		nnewSuperior = ch_strdup( newSuperior );
132

133
		if( dn_normalize( nnewSuperior ) == NULL ) {
134
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
135
136
			LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
				   "do_modrdn:  invalid new superior (%s)\n", newSuperior ));
137
#else
138
139
			Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid new superior (%s)\n",
				newSuperior, 0, 0 );
140
141
#endif

142
			send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
143
				"invalid new superior DN", NULL, NULL );
Howard Chu's avatar
Howard Chu committed
144
			goto cleanup;
145
		}
146

147
	}
148

149
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
150
151
152
	LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
		   "do_modrdn: dn (%s) newrdn (%s) newsuperior(%s)\n",
		   dn, newrdn, newSuperior != NULL ? newSuperior : "" ));
153
#else
154
155
	Debug( LDAP_DEBUG_ARGS,
	    "do_modrdn: dn (%s) newrdn (%s) newsuperior (%s)\n",
156
		dn, newrdn,
157
		newSuperior != NULL ? newSuperior : "" );
158
159
#endif

160

161
	if ( ber_scanf( op->o_ber, /*{*/ "}") == LBER_ERROR ) {
162
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
163
164
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn: ber_scanf failed\n" ));
165
#else
166
		Debug( LDAP_DEBUG_ANY, "do_modrdn: ber_scanf failed\n", 0, 0, 0 );
167
168
#endif

169
170
		send_ldap_disconnect( conn, op,
				LDAP_PROTOCOL_ERROR, "decoding error" );
171
		rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
172
		goto cleanup;
173
174
	}

175
	if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
176
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
177
178
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn: get_ctrls failed\n" ));
179
#else
180
		Debug( LDAP_DEBUG_ANY, "do_modrdn: get_ctrls failed\n", 0, 0, 0 );
181
182
#endif

Gary Williams's avatar
Gary Williams committed
183
		/* get_ctrls has sent results.	Now clean up. */
Howard Chu's avatar
Howard Chu committed
184
		goto cleanup;
185
186
	} 

187
188
189
	ndn = ch_strdup( dn );

	if( dn_normalize( ndn ) == NULL ) {
190
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
191
192
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn: invalid dn (%s)\n", dn ));
193
#else
194
		Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid dn (%s)\n", dn, 0, 0 );
195
196
#endif

197
198
199
200
201
202
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid DN", NULL, NULL );
		goto cleanup;
	}

	if( !rdn_validate( newrdn ) ) {
203
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
204
205
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn: invalid rdn (%s).\n", newrdn ));
206
#else
207
		Debug( LDAP_DEBUG_ANY, "do_modrdn: invalid rdn (%s)\n", newrdn, 0, 0 );
208
209
#endif

210
211
212
213
214
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid RDN", NULL, NULL );
		goto cleanup;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
215
	if( *ndn == '\0' ) {
216
#ifdef NEW_LOGGING
Gary Williams's avatar
Gary Williams committed
217
218
		LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
			   "do_modrdn:  attempt to modify root DSE.\n" ));
219
#else
220
		Debug( LDAP_DEBUG_ANY, "do_modrdn: root dse!\n", 0, 0, 0 );
221
222
#endif

223
224
225
226
227
		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
			NULL, "cannot rename the root DSE", NULL, NULL );
		goto cleanup;
	}

Hallvard Furuseth's avatar
Hallvard Furuseth committed
228
	Statslog( LDAP_DEBUG_STATS, "conn=%ld op=%d MODRDN dn=\"%s\"\n",
229
	    op->o_connid, op->o_opid, dn, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
230

231
232
	manageDSAit = get_manageDSAit( op );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
233
234
235
236
237
	/*
	 * 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.
	 */
238
	if ( (be = select_backend( ndn, manageDSAit )) == NULL ) {
239
240
		send_ldap_result( conn, op, rc = LDAP_REFERRAL,
			NULL, NULL, default_referral, NULL );
Howard Chu's avatar
Howard Chu committed
241
		goto cleanup;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
243
	}

244
245
	/* check restrictions */
	rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
246
247
	if( rc != LDAP_SUCCESS ) {
		send_ldap_result( conn, op, rc,
248
			NULL, text, NULL, NULL );
249
		goto cleanup;
250
251
	}

252
	/* check for referrals */
253
	rc = backend_check_referrals( be, conn, op, dn, ndn );
254
255
256
257
	if ( rc != LDAP_SUCCESS ) {
		goto cleanup;
	}

258
259
260
	/* Make sure that the entry being changed and the newSuperior are in 
	 * the same backend, otherwise we return an error.
	 */
261
	if( newSuperior != NULL ) {
262
		newSuperior_be = select_backend( nnewSuperior, 0 );
263

264
		if ( newSuperior_be != be ) {
265
266
			/* newSuperior is in same backend */
			rc = LDAP_AFFECTS_MULTIPLE_DSAS;
267

268
			send_ldap_result( conn, op, rc,
269
				NULL, "cannot rename between DSAa", NULL, NULL );
270

Howard Chu's avatar
Howard Chu committed
271
			goto cleanup;
272
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
273
274
275

		/* deref suffix alias if appropriate */
		nnewSuperior = suffix_alias( be, nnewSuperior );
276
	}
277

Kurt Zeilenga's avatar
Kurt Zeilenga committed
278
279
280
	/* deref suffix alias if appropriate */
	ndn = suffix_alias( be, ndn );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
281
282
283
284
	/*
	 * 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;
285
	 * 3) it's a replica and the dn supplied is the update_ndn.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
286
	 */
287
	if ( be->be_modrdn ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
		/* do the update here */
289
#ifndef SLAPD_MULTIMASTER
290
291
		if ( be->be_update_ndn == NULL ||
			strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
292
#endif
293
		{
294
			if ( (*be->be_modrdn)( be, conn, op, dn, ndn, newrdn,
295
296
297
298
299
300
			    deloldrdn, newSuperior ) == 0
#ifdef SLAPD_MULTIMASTER
				&& ( be->be_update_ndn == NULL ||
					strcmp( be->be_update_ndn, op->o_ndn ) )
#endif
			) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
301
				struct replog_moddn moddn;
Gary Williams's avatar
Gary Williams committed
302
				moddn.newrdn = newrdn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
304
				moddn.deloldrdn = deloldrdn;
				moddn.newsup = newSuperior;
305

306
				replog( be, op, dn, &moddn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
307
			}
308
#ifndef SLAPD_MULTIMASTER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309
		} else {
310
311
			send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
				be->be_update_refs ? be->be_update_refs : default_referral, NULL );
312
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
313
314
		}
	} else {
315
		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
316
			NULL, "operation not supported within namingContext", NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
317
318
	}

Howard Chu's avatar
Howard Chu committed
319
cleanup:
320
	free( dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
321
	if( ndn != NULL ) free( ndn );
322
	free( newrdn );	
Howard Chu's avatar
Howard Chu committed
323
324
325
326
	if ( newSuperior != NULL )
		free( newSuperior );
	if ( nnewSuperior != NULL )
		free( nnewSuperior );
327
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
}