modify.c 22.5 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2003 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.
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
18
19
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
20
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
21
22
23
24
25

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

26
#include "ldap_pvt.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
#include "slap.h"
28
#ifdef LDAP_SLAPI
29
#include "slapi.h"
30
#endif
31
32
#include "lutil.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
33

34
int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35
36
do_modify(
    Connection	*conn,
37
    Operation	*op )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38
{
39
	struct berval dn = { 0, NULL };
Howard Chu's avatar
Howard Chu committed
40
41
	struct berval pdn = { 0, NULL };
	struct berval ndn = { 0, NULL };
Kurt Zeilenga's avatar
Kurt Zeilenga committed
42
	char		*last;
43
44
	ber_tag_t	tag;
	ber_len_t	len;
45
46
	Modifications	*modlist = NULL;
	Modifications	**modtail = &modlist;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
#ifdef LDAP_DEBUG
48
	Modifications *tmp;
49
50
51
52
#endif
#ifdef LDAP_SLAPI
	LDAPMod		**modv = NULL;
	Slapi_PBlock *pb = op->o_pb;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
	Backend		*be;
55
	int rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
	const char	*text;
57
	int manageDSAit;
58

59
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
60
	LDAP_LOG( OPERATION, ENTRY, "do_modify: enter\n", 0, 0, 0 );
61
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
	Debug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
63
64
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
	/*
	 * Parse the modify request.  It looks like this:
	 *
	 *	ModifyRequest := [APPLICATION 6] SEQUENCE {
	 *		name	DistinguishedName,
	 *		mods	SEQUENCE OF SEQUENCE {
	 *			operation	ENUMERATED {
	 *				add	(0),
	 *				delete	(1),
	 *				replace	(2)
	 *			},
	 *			modification	SEQUENCE {
	 *				type	AttributeType,
	 *				values	SET OF AttributeValue
	 *			}
	 *		}
	 *	}
	 */

84
	if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
85
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
86
		LDAP_LOG( OPERATION, ERR, "do_modify: ber_scanf failed\n", 0, 0, 0 );
87
#else
88
		Debug( LDAP_DEBUG_ANY, "do_modify: ber_scanf failed\n", 0, 0, 0 );
89
90
#endif

91
92
		send_ldap_disconnect( conn, op,
			LDAP_PROTOCOL_ERROR, "decoding error" );
93
		return SLAPD_DISCONNECT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
94
95
	}

96
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
97
	LDAP_LOG( OPERATION, ARGS, "do_modify: dn (%s)\n", dn.bv_val, 0, 0 );
98
#else
99
	Debug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn.bv_val, 0, 0 );
100
101
#endif

102

Kurt Zeilenga's avatar
Kurt Zeilenga committed
103
	/* collect modifications & save for later */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
104

Kurt Zeilenga's avatar
Kurt Zeilenga committed
105
106
107
108
	for ( tag = ber_first_element( op->o_ber, &len, &last );
	    tag != LBER_DEFAULT;
	    tag = ber_next_element( op->o_ber, &len, last ) )
	{
109
		ber_int_t mop;
110
		Modifications tmp, *mod;
111

Kurt Zeilenga's avatar
Kurt Zeilenga committed
112
113
114
#ifdef SLAP_NVALUES
		tmp.sml_nvalues = NULL;
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
115

116
		if ( ber_scanf( op->o_ber, "{i{m[W]}}", &mop,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
117
		    &tmp.sml_type, &tmp.sml_values )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
119
		    == LBER_ERROR )
		{
120
121
			send_ldap_disconnect( conn, op,
				LDAP_PROTOCOL_ERROR, "decoding modlist error" );
122
			rc = SLAPD_DISCONNECT;
Howard Chu's avatar
Howard Chu committed
123
			goto cleanup;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
124
125
		}

Howard Chu's avatar
Howard Chu committed
126
		mod = (Modifications *) ch_malloc( sizeof(Modifications) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
127
		mod->sml_op = mop;
Howard Chu's avatar
Howard Chu committed
128
		mod->sml_type = tmp.sml_type;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
130
131
132
		mod->sml_values = tmp.sml_values;
#ifdef SLAP_NVALUES
		mod->sml_nvalues = NULL;
#endif
133
		mod->sml_desc = NULL;
134
		mod->sml_next = NULL;
135
136
		*modtail = mod;

137
138
		switch( mop ) {
		case LDAP_MOD_ADD:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
139
			if ( mod->sml_values == NULL ) {
140
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
141
				LDAP_LOG( OPERATION, ERR, 
142
					"do_modify: modify/add operation (%ld) requires values\n",
Julius Enarusai's avatar
   
Julius Enarusai committed
143
					(long)mop, 0, 0 );
144
#else
145
146
147
				Debug( LDAP_DEBUG_ANY,
					"do_modify: modify/add operation (%ld) requires values\n",
					(long) mop, 0, 0 );
148
149
#endif

150
151
152
153
154
155
				send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
					NULL, "modify/add operation requires values",
					NULL, NULL );
				rc = LDAP_PROTOCOL_ERROR;
				goto cleanup;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
156

157
158
159
160
161
162
163
			/* fall through */

		case LDAP_MOD_DELETE:
		case LDAP_MOD_REPLACE:
			break;

		default: {
164
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
165
166
				LDAP_LOG( OPERATION, ERR, 
					"do_modify: invalid modify operation (%ld)\n", (long)mop, 0, 0 );
167
#else
168
169
170
				Debug( LDAP_DEBUG_ANY,
					"do_modify: invalid modify operation (%ld)\n",
					(long) mop, 0, 0 );
171
172
#endif

173
174
175
176
177
				send_ldap_result( conn, op, LDAP_PROTOCOL_ERROR,
					NULL, "unrecognized modify operation", NULL, NULL );
				rc = LDAP_PROTOCOL_ERROR;
				goto cleanup;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
178
		}
179

180
		modtail = &mod->sml_next;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181
182
183
	}
	*modtail = NULL;

184
	if( (rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
185
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
186
		LDAP_LOG( OPERATION, ERR, "do_modify: get_ctrls failed\n", 0, 0, 0 );
187
#else
188
		Debug( LDAP_DEBUG_ANY, "do_modify: get_ctrls failed\n", 0, 0, 0 );
189
190
#endif

191
192
193
		goto cleanup;
	}

Howard Chu's avatar
Howard Chu committed
194
	rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn );
195
	if( rc != LDAP_SUCCESS ) {
196
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
197
198
		LDAP_LOG( OPERATION, INFO, "do_modify: conn %d  invalid dn (%s)\n",
			conn->c_connid, dn.bv_val, 0 );
199
#else
200
		Debug( LDAP_DEBUG_ANY,
201
			"do_modify: invalid dn (%s)\n", dn.bv_val, 0, 0 );
202
#endif
203
204
205
206
		send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
		    "invalid DN", NULL, NULL );
		goto cleanup;
	}
207

Howard Chu's avatar
Howard Chu committed
208
	if( ndn.bv_len == 0 ) {
209
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
210
211
		LDAP_LOG( OPERATION, ERR, 
			"do_modify: attempt to modify root DSE.\n",0, 0, 0 );
212
#else
213
		Debug( LDAP_DEBUG_ANY, "do_modify: root dse!\n", 0, 0, 0 );
214
215
#endif

216
217
218
		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
			NULL, "modify upon the root DSE not supported", NULL, NULL );
		goto cleanup;
219

220
	} else if ( bvmatch( &ndn, &global_schemandn ) ) {
221
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
222
223
		LDAP_LOG( OPERATION, ERR,
			"do_modify: attempt to modify subschema subentry.\n" , 0, 0, 0  );
224
225
226
227
228
229
230
231
#else
		Debug( LDAP_DEBUG_ANY, "do_modify: subschema subentry!\n", 0, 0, 0 );
#endif

		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
			NULL, "modification of subschema subentry not supported",
			NULL, NULL );
		goto cleanup;
232
233
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
234
#ifdef LDAP_DEBUG
235
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
236
	LDAP_LOG( OPERATION, DETAIL1, "do_modify: modifications:\n", 0, 0, 0  );
237
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
238
	Debug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
239
240
#endif

241
	for ( tmp = modlist; tmp != NULL; tmp = tmp->sml_next ) {
242
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
243
244
245
246
		LDAP_LOG( OPERATION, DETAIL1, "\t%s:  %s\n", 
			tmp->sml_op == LDAP_MOD_ADD ?
			"add" : (tmp->sml_op == LDAP_MOD_DELETE ?
			"delete" : "replace"), tmp->sml_type.bv_val, 0 );
247

Kurt Zeilenga's avatar
Kurt Zeilenga committed
248
		if ( tmp->sml_values == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
249
			LDAP_LOG( OPERATION, DETAIL1, "\t\tno values", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
250
		} else if ( tmp->sml_values[0].bv_val == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
251
			LDAP_LOG( OPERATION, DETAIL1, "\t\tzero values", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
252
		} else if ( tmp->sml_values[1].bv_val == NULL ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
253
			LDAP_LOG( OPERATION, DETAIL1, "\t\tone value", 0, 0, 0 );
254
		} else {
Julius Enarusai's avatar
   
Julius Enarusai committed
255
			LDAP_LOG( OPERATION, DETAIL1, "\t\tmultiple values", 0, 0, 0 );
256
257
		}

258
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
259
		Debug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
260
261
262
			tmp->sml_op == LDAP_MOD_ADD
				? "add" : (tmp->sml_op == LDAP_MOD_DELETE
					? "delete" : "replace"), tmp->sml_type.bv_val, 0 );
263

Kurt Zeilenga's avatar
Kurt Zeilenga committed
264
		if ( tmp->sml_values == NULL ) {
265
266
			Debug( LDAP_DEBUG_ARGS, "%s\n",
			   "\t\tno values", NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
267
		} else if ( tmp->sml_values[0].bv_val == NULL ) {
268
269
			Debug( LDAP_DEBUG_ARGS, "%s\n",
			   "\t\tzero values", NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
270
		} else if ( tmp->sml_values[1].bv_val == NULL ) {
271
			Debug( LDAP_DEBUG_ARGS, "%s, length %ld\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
			   "\t\tone value", (long) tmp->sml_values[0].bv_len, NULL );
273
274
275
276
277
		} else {
			Debug( LDAP_DEBUG_ARGS, "%s\n",
			   "\t\tmultiple values", NULL, NULL );
		}
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
278
279
	}

Howard Chu's avatar
Howard Chu committed
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
	if ( StatslogTest( LDAP_DEBUG_STATS ) ) {
		char abuf[BUFSIZ/2], *ptr = abuf;
		int len = 0;

		Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD dn=\"%s\"\n",
			op->o_connid, op->o_opid, dn.bv_val, 0, 0 );

		for ( tmp = modlist; tmp != NULL; tmp = tmp->sml_next ) {
			if (len + 1 + tmp->sml_type.bv_len > sizeof(abuf)) {
				Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD attr=%s\n",
				    op->o_connid, op->o_opid, abuf, 0, 0 );
	    			len = 0;
				ptr = abuf;
			}
			if (len) {
				*ptr++ = ' ';
				len++;
			}
			ptr = lutil_strcopy(ptr, tmp->sml_type.bv_val);
			len += tmp->sml_type.bv_len;
		}
		if (len) {
			Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu MOD attr=%s\n",
	    			op->o_connid, op->o_opid, abuf, 0, 0 );
		}
	}
Howard Chu's avatar
Howard Chu committed
306
#endif	/* LDAP_DEBUG */
307

308
309
	manageDSAit = get_manageDSAit( op );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
310
311
312
313
314
	/*
	 * 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.
	 */
Howard Chu's avatar
Howard Chu committed
315
	if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) {
316
		BerVarray ref = referral_rewrite( default_referral,
Howard Chu's avatar
Howard Chu committed
317
			NULL, &pdn, LDAP_SCOPE_DEFAULT );
318

319
		send_ldap_result( conn, op, rc = LDAP_REFERRAL,
320
321
			NULL, NULL, ref ? ref : default_referral, NULL );

322
		ber_bvarray_free( ref );
Howard Chu's avatar
Howard Chu committed
323
		goto cleanup;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
324
325
	}

326
327
	/* check restrictions */
	rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
328
329
	if( rc != LDAP_SUCCESS ) {
		send_ldap_result( conn, op, rc,
330
			NULL, text, NULL, NULL );
331
		goto cleanup;
332
333
	}

334
	/* check for referrals */
Howard Chu's avatar
Howard Chu committed
335
	rc = backend_check_referrals( be, conn, op, &pdn, &ndn );
336
337
338
339
	if ( rc != LDAP_SUCCESS ) {
		goto cleanup;
	}

340
#if defined( LDAP_SLAPI )
341
342
343
	slapi_x_backend_set_pb( pb, be );
	slapi_x_connection_set_pb( pb, conn );
	slapi_x_operation_set_pb( pb, op );
344
	slapi_pblock_set( pb, SLAPI_MODIFY_TARGET, (void *)dn.bv_val );
345
	slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)manageDSAit );
346
	modv = slapi_x_modifications2ldapmods( &modlist );
347
	slapi_pblock_set( pb, SLAPI_MODIFY_MODS, (void *)modv );
348
349

	rc = doPluginFNs( be, SLAPI_PLUGIN_PRE_MODIFY_FN, pb );
350
	if ( rc != 0 ) {
351
		/*
352
353
		 * A preoperation plugin failure will abort the
		 * entire operation.
354
355
		 */
#ifdef NEW_LOGGING
356
		LDAP_LOG( OPERATION, INFO, "do_modify: modify preoperation plugin "
357
				"failed\n", 0, 0, 0 );
358
#else
359
		Debug(LDAP_DEBUG_TRACE, "do_modify: modify preoperation plugin failed.\n",
360
				0, 0, 0);
361
#endif
362
		if ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rc ) != 0) {
363
			rc = LDAP_OTHER;
364
365
366
		}
		ldap_mods_free( modv, 1 );
		modv = NULL;
367
		goto cleanup;
368
	}
369
370
371
372
373
374

	/*
	 * It's possible that the preoperation plugin changed the
	 * modification array, so we need to convert it back to
	 * a Modification list.
	 *
375
	 * Calling slapi_x_modifications2ldapmods() destroyed modlist so
376
377
378
	 * we don't need to free it.
	 */
	slapi_pblock_get( pb, SLAPI_MODIFY_MODS, (void **)&modv );
379
	modlist = slapi_x_ldapmods2modifications( modv );
380
381
#endif /* defined( LDAP_SLAPI ) */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
382
383
384
385
	/*
	 * do the modify if 1 && (2 || 3)
	 * 1) there is a modify function implemented in this backend;
	 * 2) this backend is master for what it holds;
386
	 * 3) it's a replica and the dn supplied is the update_ndn.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
387
	 */
388
	if ( be->be_modify ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
389
		/* do the update here */
390
		int repl_user = be_isupdate( be, &op->o_ndn );
391
#ifndef SLAPD_MULTIMASTER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
392
393
		/* Multimaster slapd does not have to check for replicator dn
		 * because it accepts each modify request
394
		 */
395
		if ( !be->be_update_ndn.bv_len || repl_user )
396
#endif
397
		{
398
			int update = be->be_update_ndn.bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
399
			const char *text;
400
401
402
			char textbuf[SLAP_TEXT_BUFLEN];
			size_t textlen = sizeof textbuf;

403
			rc = slap_mods_check( modlist, update, &text,
404
				textbuf, textlen );
405
406
407
408
409
410
411

			if( rc != LDAP_SUCCESS ) {
				send_ldap_result( conn, op, rc,
					NULL, text, NULL, NULL );
				goto cleanup;
			}

412
			if ( !repl_user ) {
413
414
415
				for( modtail = &modlist;
					*modtail != NULL;
					modtail = &(*modtail)->sml_next )
416
417
418
				{
					/* empty */
				}
419

420
				rc = slap_mods_opattrs( be, op, modlist, modtail, &text,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
421
					textbuf, textlen );
422
423
				if( rc != LDAP_SUCCESS ) {
					send_ldap_result( conn, op, rc,
424
						NULL, text,
425
						NULL, NULL );
Howard Chu's avatar
Howard Chu committed
426
					goto cleanup;
427
428
429
				}
			}

430
			if ( (*be->be_modify)( be, conn, op, &pdn, &ndn, modlist ) == 0
431
#ifdef SLAPD_MULTIMASTER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
432
				&& !repl_user
433
434
435
#endif
			) {
				/* but we log only the ones not from a replicator user */
436
				replog( be, op, &pdn, &ndn, modlist );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437
438
			}

439
#ifndef SLAPD_MULTIMASTER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
440
441
		/* send a referral */
		} else {
442
			BerVarray defref = be->be_update_refs
443
				? be->be_update_refs : default_referral;
444
			BerVarray ref = referral_rewrite( defref,
Howard Chu's avatar
Howard Chu committed
445
				NULL, &pdn, LDAP_SCOPE_DEFAULT );
446

447
			send_ldap_result( conn, op, rc = LDAP_REFERRAL, NULL, NULL,
448
449
				ref ? ref : defref, NULL );

450
			ber_bvarray_free( ref );
451
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
452
453
		}
	} else {
454
		send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
455
456
		    NULL, "operation not supported within namingContext",
			NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
457
458
	}

459
#if defined( LDAP_SLAPI )
460
	if ( doPluginFNs( be, SLAPI_PLUGIN_POST_MODIFY_FN, pb ) != 0 ) {
461
#ifdef NEW_LOGGING
462
		LDAP_LOG( OPERATION, INFO, "do_modify: modify postoperation plugins "
463
				"failed\n", 0, 0, 0 );
464
#else
465
		Debug(LDAP_DEBUG_TRACE, "do_modify: modify postoperation plugins "
466
				"failed.\n", 0, 0, 0);
467
468
469
470
#endif
	}
#endif /* defined( LDAP_SLAPI ) */

Howard Chu's avatar
Howard Chu committed
471
cleanup:
Howard Chu's avatar
Howard Chu committed
472
473
	free( pdn.bv_val );
	free( ndn.bv_val );
474
	if ( modlist != NULL ) slap_mods_free( modlist );
475
#if defined( LDAP_SLAPI )
476
	if ( modv != NULL ) slapi_x_free_ldapmods( modv );
477
#endif
478
	return rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
479
480
}

481
482
483
/*
 * Do basic attribute type checking and syntax validation.
 */
484
485
int slap_mods_check(
	Modifications *ml,
486
	int update,
487
	const char **text,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
489
	char *textbuf,
	size_t textlen )
490
491
492
{
	int rc;

493
	for( ; ml != NULL; ml = ml->sml_next ) {
494
		AttributeDescription *ad = NULL;
495
496

		/* convert to attribute description */
497
		rc = slap_bv2ad( &ml->sml_type, &ml->sml_desc, text );
498
499

		if( rc != LDAP_SUCCESS ) {
500
			snprintf( textbuf, textlen, "%s: %s",
501
				ml->sml_type.bv_val, *text );
502
			*text = textbuf;
503
504
505
			return rc;
		}

506
		ad = ml->sml_desc;
507

508
509
		if( slap_syntax_is_binary( ad->ad_type->sat_syntax )
			&& !slap_ad_is_binary( ad ))
510
511
		{
			/* attribute requires binary transfer */
512
513
			snprintf( textbuf, textlen,
				"%s: requires ;binary transfer",
514
				ml->sml_type.bv_val );
515
			*text = textbuf;
516
517
518
			return LDAP_UNDEFINED_TYPE;
		}

519
520
521
522
		if( !slap_syntax_is_binary( ad->ad_type->sat_syntax )
			&& slap_ad_is_binary( ad ))
		{
			/* attribute requires binary transfer */
523
524
			snprintf( textbuf, textlen,
				"%s: disallows ;binary transfer",
525
				ml->sml_type.bv_val );
526
			*text = textbuf;
527
528
529
			return LDAP_UNDEFINED_TYPE;
		}

530
		if( slap_ad_is_tag_range( ad )) {
531
532
			/* attribute requires binary transfer */
			snprintf( textbuf, textlen,
533
				"%s: inappropriate use of tag range option",
534
535
536
537
538
				ml->sml_type.bv_val );
			*text = textbuf;
			return LDAP_UNDEFINED_TYPE;
		}

539
540
		if (!update && is_at_no_user_mod( ad->ad_type )) {
			/* user modification disallowed */
541
542
			snprintf( textbuf, textlen,
				"%s: no user modification allowed",
543
				ml->sml_type.bv_val );
544
			*text = textbuf;
545
546
547
			return LDAP_CONSTRAINT_VIOLATION;
		}

548
		if ( is_at_obsolete( ad->ad_type ) &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
			( ml->sml_op == LDAP_MOD_ADD || ml->sml_values != NULL ) )
550
551
552
553
554
555
556
		{
			/*
			 * attribute is obsolete,
			 * only allow replace/delete with no values
			 */
			snprintf( textbuf, textlen,
				"%s: attribute is obsolete",
557
				ml->sml_type.bv_val );
558
559
560
561
			*text = textbuf;
			return LDAP_CONSTRAINT_VIOLATION;
		}

562
563
564
		/*
		 * check values
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
565
		if( ml->sml_values != NULL ) {
566
567
568
			ber_len_t nvals;
			slap_syntax_validate_func *validate =
				ad->ad_type->sat_syntax->ssyn_validate;
569
570
571
572
			slap_syntax_transform_func *pretty =
				ad->ad_type->sat_syntax->ssyn_pretty;
 
			if( !pretty && !validate ) {
573
				*text = "no validator for syntax";
574
575
				snprintf( textbuf, textlen,
					"%s: no validator for syntax %s",
576
					ml->sml_type.bv_val,
577
578
					ad->ad_type->sat_syntax->ssyn_oid );
				*text = textbuf;
579
580
581
				return LDAP_INVALID_SYNTAX;
			}

582
583
			/*
			 * check that each value is valid per syntax
584
			 *	and pretty if appropriate
585
			 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
586
			for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
587
				struct berval pval;
588
589
				if( pretty ) {
					rc = pretty( ad->ad_type->sat_syntax,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
590
						&ml->sml_values[nvals], &pval );
591
592
				} else {
					rc = validate( ad->ad_type->sat_syntax,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
593
						&ml->sml_values[nvals] );
594
				}
595
596

				if( rc != 0 ) {
597
					snprintf( textbuf, textlen,
598
						"%s: value #%ld invalid per syntax",
599
						ml->sml_type.bv_val, (long) nvals );
600
					*text = textbuf;
601
602
					return LDAP_INVALID_SYNTAX;
				}
603
604

				if( pretty ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
605
606
					ber_memfree( ml->sml_values[nvals].bv_val );
					ml->sml_values[nvals] = pval;
607
				}
608
609
			}

610
611
612
613
614
615
616
617
618
619
620
621
622
623
			/*
			 * a rough single value check... an additional check is needed
			 * to catch add of single value to existing single valued attribute
			 */
			if ((ml->sml_op == LDAP_MOD_ADD || ml->sml_op == LDAP_MOD_REPLACE)
				&& nvals > 1 && is_at_single_value( ad->ad_type ))
			{
				snprintf( textbuf, textlen,
					"%s: multiple values provided",
					ml->sml_type.bv_val );
				*text = textbuf;
				return LDAP_CONSTRAINT_VIOLATION;
			}

624
625
#ifdef SLAP_NVALUES
			if( nvals && ad->ad_type->sat_equality &&
Kurt Zeilenga's avatar
Kurt Zeilenga committed
626
				ad->ad_type->sat_equality->smr_normalize )
627
628
			{
				ml->sml_nvalues = ch_malloc( (nvals+1)*sizeof(struct berval) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
629
				for( nvals = 0; ml->sml_values[nvals].bv_val; nvals++ ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
630
631
					rc = ad->ad_type->sat_equality->smr_normalize(
						0,
632
						ad->ad_type->sat_syntax,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
633
						ad->ad_type->sat_equality,
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
						&ml->sml_values[nvals], &ml->sml_nvalues[nvals] );
					if( rc ) {
#ifdef NEW_LOGGING
						LDAP_LOG( OPERATION, DETAIL1,
							"str2entry:  NULL (ssyn_normalize %d)\n",
							rc, 0, 0 );
#else
						Debug( LDAP_DEBUG_ANY,
							"<= str2entry NULL (ssyn_normalize %d)\n",
							rc, 0, 0 );
#endif
						snprintf( textbuf, textlen,
							"%s: value #%ld normalization failed",
							ml->sml_type.bv_val, (long) nvals );
						*text = textbuf;
						return rc;
					}
				}
652
653
				ml->sml_nvalues[nvals].bv_val = NULL;
				ml->sml_nvalues[nvals].bv_len = 0;
654
655
			}
#endif
656
657
658
659
660
661
662
		}
	}

	return LDAP_SUCCESS;
}

int slap_mods_opattrs(
663
	Backend *be,
664
	Operation *op,
665
	Modifications *mods,
666
	Modifications **modtail,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
668
	const char **text,
	char *textbuf, size_t textlen )
669
{
670
	struct berval name, timestamp, csn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
671
672
673
#ifdef SLAP_NVALUES
	struct berval nname;
#endif
674
675
	char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
	char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
676
677
678
679
680
	Modifications *mod;

	int mop = op->o_tag == LDAP_REQ_ADD
		? LDAP_MOD_ADD : LDAP_MOD_REPLACE;

681
682
683
	assert( modtail != NULL );
	assert( *modtail == NULL );

684
685
686
	if( SLAP_LASTMOD(be) ) {
		struct tm *ltm;
		time_t now = slap_get_time();
687

688
689
		ldap_pvt_thread_mutex_lock( &gmtime_mutex );
		ltm = gmtime( &now );
Howard Chu's avatar
Howard Chu committed
690
		lutil_gentime( timebuf, sizeof(timebuf), ltm );
691

692
693
694
		csn.bv_len = lutil_csnstr( csnbuf, sizeof( csnbuf ), 0, 0 );
		ldap_pvt_thread_mutex_unlock( &gmtime_mutex );
		csn.bv_val = csnbuf;
695

696
697
698
699
700
701
		timestamp.bv_val = timebuf;
		timestamp.bv_len = strlen(timebuf);

		if( op->o_dn.bv_len == 0 ) {
			name.bv_val = SLAPD_ANONYMOUS;
			name.bv_len = sizeof(SLAPD_ANONYMOUS)-1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
702
703
704
#ifdef SLAP_NVALUES
			nname = name;
#endif
705
706
		} else {
			name = op->o_dn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
708
709
#ifdef SLAP_NVALUES
			nname = op->o_ndn;
#endif
710
		}
711
712
713
	}

	if( op->o_tag == LDAP_REQ_ADD ) {
714
		struct berval tmpval;
715

716
717
718
719
720
721
		if( global_schemacheck ) {
			int rc = mods_structural_class( mods, &tmpval,
				text, textbuf, textlen );
			if( rc != LDAP_SUCCESS ) {
				return rc;
			}
722
723
724
725
726

			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_op = mop;
			mod->sml_type.bv_val = NULL;
			mod->sml_desc = slap_schema.si_ad_structuralObjectClass;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
727
728
			mod->sml_values =
				(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
729
			ber_dupbv( &mod->sml_values[0], &tmpval );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
730
			mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
731
732
			mod->sml_values[1].bv_val = NULL;
			assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
733
734
735
736
737
738
739
740
#ifdef SLAP_NVALUES
			mod->sml_nvalues =
				(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_nvalues[0], &tmpval );
			mod->sml_nvalues[1].bv_len = 0;
			mod->sml_nvalues[1].bv_val = NULL;
			assert( mod->sml_nvalues[0].bv_val );
#endif
741
742
			*modtail = mod;
			modtail = &mod->sml_next;
743
		}
744
745

		if( SLAP_LASTMOD(be) ) {
746
			char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
747
748
749
750

			tmpval.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
			tmpval.bv_val = uuidbuf;
		
751
			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
752
			mod->sml_op = mop;
Howard Chu's avatar
Howard Chu committed
753
			mod->sml_type.bv_val = NULL;
754
			mod->sml_desc = slap_schema.si_ad_entryUUID;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
755
756
			mod->sml_values =
				(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
757
			ber_dupbv( &mod->sml_values[0], &tmpval );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
758
			mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
759
760
			mod->sml_values[1].bv_val = NULL;
			assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
761
762
763
#ifdef SLAP_NVALUES
			mod->sml_nvalues = NULL;
#endif
764
765
			*modtail = mod;
			modtail = &mod->sml_next;
766
767
768
769
770

			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_op = mop;
			mod->sml_type.bv_val = NULL;
			mod->sml_desc = slap_schema.si_ad_creatorsName;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
771
772
			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_values[0], &name );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
773
			mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
774
775
			mod->sml_values[1].bv_val = NULL;
			assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
776
777
778
779
780
781
782
783
#ifdef SLAP_NVALUES
			mod->sml_nvalues =
				(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_nvalues[0], &nname );
			mod->sml_nvalues[1].bv_len = 0;
			mod->sml_nvalues[1].bv_val = NULL;
			assert( mod->sml_nvalues[0].bv_val );
#endif
784
785
786
787
788
789
790
			*modtail = mod;
			modtail = &mod->sml_next;

			mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
			mod->sml_op = mop;
			mod->sml_type.bv_val = NULL;
			mod->sml_desc = slap_schema.si_ad_createTimestamp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
791
792
			mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
			ber_dupbv( &mod->sml_values[0], &timestamp );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
793
			mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
794
795
			mod->sml_values[1].bv_val = NULL;
			assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
796
797
798
#ifdef SLAP_NVALUES
			mod->sml_nvalues = NULL;
#endif
799
800
			*modtail = mod;
			modtail = &mod->sml_next;
801
		}
802
	}
803

804
	if( SLAP_LASTMOD(be) ) {
805
		mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
806
		mod->sml_op = mop;
Howard Chu's avatar
Howard Chu committed
807
		mod->sml_type.bv_val = NULL;
808
		mod->sml_desc = slap_schema.si_ad_entryCSN;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
809
810
		mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
		ber_dupbv( &mod->sml_values[0], &csn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
811
		mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
812
813
		mod->sml_values[1].bv_val = NULL;
		assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
814
815
816
#ifdef SLAP_NVALUES
		mod->sml_nvalues = NULL;
#endif
817
818
819
		*modtail = mod;
		modtail = &mod->sml_next;

820
		mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
821
		mod->sml_op = mop;
Howard Chu's avatar
Howard Chu committed
822
		mod->sml_type.bv_val = NULL;
823
		mod->sml_desc = slap_schema.si_ad_modifiersName;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
824
825
		mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
		ber_dupbv( &mod->sml_values[0], &name );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
		mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
827
828
		mod->sml_values[1].bv_val = NULL;
		assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
829
830
831
832
833
834
835
836
#ifdef SLAP_NVALUES
		mod->sml_nvalues =
			(BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
		ber_dupbv( &mod->sml_nvalues[0], &nname );
		mod->sml_nvalues[1].bv_len = 0;
		mod->sml_nvalues[1].bv_val = NULL;
		assert( mod->sml_nvalues[0].bv_val );
#endif
837
838
839
		*modtail = mod;
		modtail = &mod->sml_next;

840
		mod = (Modifications *) ch_malloc( sizeof( Modifications ) );
841
		mod->sml_op = mop;
Howard Chu's avatar
Howard Chu committed
842
		mod->sml_type.bv_val = NULL;
843
		mod->sml_desc = slap_schema.si_ad_modifyTimestamp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
844
845
		mod->sml_values = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
		ber_dupbv( &mod->sml_values[0], &timestamp );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
846
		mod->sml_values[1].bv_len = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
847
848
		mod->sml_values[1].bv_val = NULL;
		assert( mod->sml_values[0].bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
849
850
851
#ifdef SLAP_NVALUES
		mod->sml_nvalues = NULL;
#endif
852
853
854
855
		*modtail = mod;
		modtail = &mod->sml_next;
	}

856
	*modtail = NULL;
857
858
	return LDAP_SUCCESS;
}
859