xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/add.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: add.c,v 1.1.1.4 2014/05/28 09:58:45 tron Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2014 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms are permitted
21  * provided that this notice is preserved and that due credit is given
22  * to the University of Michigan at Ann Arbor. The name of the University
23  * may not be used to endorse or promote products derived from this
24  * software without specific prior written permission. This software
25  * is provided ``as is'' without express or implied warranty.
26  */
27 
28 #include "portable.h"
29 
30 #include <stdio.h>
31 #include <ac/string.h>
32 #include <ac/time.h>
33 #include <ac/socket.h>
34 
35 #include "lutil.h"
36 #include "slap.h"
37 
38 int
39 do_add( Operation *op, SlapReply *rs )
40 {
41 	BerElement	*ber = op->o_ber;
42 	char		*last;
43 	struct berval	dn = BER_BVNULL;
44 	ber_len_t	len;
45 	ber_tag_t	tag;
46 	Modifications	*modlist = NULL;
47 	Modifications	**modtail = &modlist;
48 	Modifications	tmp;
49 	char		textbuf[ SLAP_TEXT_BUFLEN ];
50 	size_t		textlen = sizeof( textbuf );
51 	int		rc = 0;
52 	int		freevals = 1;
53 	OpExtraDB oex;
54 
55 	Debug( LDAP_DEBUG_TRACE, "%s do_add\n",
56 		op->o_log_prefix, 0, 0 );
57 
58 	/*
59 	 * Parse the add request.  It looks like this:
60 	 *
61 	 *	AddRequest := [APPLICATION 14] SEQUENCE {
62 	 *		name	DistinguishedName,
63 	 *		attrs	SEQUENCE OF SEQUENCE {
64 	 *			type	AttributeType,
65 	 *			values	SET OF AttributeValue
66 	 *		}
67 	 *	}
68 	 */
69 
70 	/* get the name */
71 	if ( ber_scanf( ber, "{m", /*}*/ &dn ) == LBER_ERROR ) {
72 		Debug( LDAP_DEBUG_ANY, "%s do_add: ber_scanf failed\n",
73 			op->o_log_prefix, 0, 0 );
74 		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
75 		return SLAPD_DISCONNECT;
76 	}
77 
78 	Debug( LDAP_DEBUG_ARGS, "%s do_add: dn (%s)\n",
79 		op->o_log_prefix, dn.bv_val, 0 );
80 
81 	/* get the attrs */
82 	for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
83 	    tag = ber_next_element( ber, &len, last ) )
84 	{
85 		Modifications *mod;
86 		ber_tag_t rtag;
87 
88 		tmp.sml_nvalues = NULL;
89 
90 		rtag = ber_scanf( ber, "{m{W}}", &tmp.sml_type, &tmp.sml_values );
91 
92 		if ( rtag == LBER_ERROR ) {
93 			Debug( LDAP_DEBUG_ANY, "%s do_add: decoding error\n",
94 				op->o_log_prefix, 0, 0 );
95 			send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
96 			rs->sr_err = SLAPD_DISCONNECT;
97 			goto done;
98 		}
99 
100 		if ( tmp.sml_values == NULL ) {
101 			Debug( LDAP_DEBUG_ANY, "%s do_add: no values for type %s\n",
102 				op->o_log_prefix, tmp.sml_type.bv_val, 0 );
103 			send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
104 				"no values for attribute type" );
105 			goto done;
106 		}
107 
108 		mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
109 		mod->sml_op = LDAP_MOD_ADD;
110 		mod->sml_flags = 0;
111 		mod->sml_next = NULL;
112 		mod->sml_desc = NULL;
113 		mod->sml_type = tmp.sml_type;
114 		mod->sml_values = tmp.sml_values;
115 		mod->sml_nvalues = NULL;
116 
117 		*modtail = mod;
118 		modtail = &mod->sml_next;
119 	}
120 
121 	if ( ber_scanf( ber, /*{*/ "}") == LBER_ERROR ) {
122 		Debug( LDAP_DEBUG_ANY, "%s do_add: ber_scanf failed\n",
123 			op->o_log_prefix, 0, 0 );
124 		send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
125 		rs->sr_err = SLAPD_DISCONNECT;
126 		goto done;
127 	}
128 
129 	if ( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
130 		Debug( LDAP_DEBUG_ANY, "%s do_add: get_ctrls failed\n",
131 			op->o_log_prefix, 0, 0 );
132 		goto done;
133 	}
134 
135 	rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn,
136 		op->o_tmpmemctx );
137 
138 	if ( rs->sr_err != LDAP_SUCCESS ) {
139 		Debug( LDAP_DEBUG_ANY, "%s do_add: invalid dn (%s)\n",
140 			op->o_log_prefix, dn.bv_val, 0 );
141 		send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
142 		goto done;
143 	}
144 
145 	op->ora_e = entry_alloc();
146 	ber_dupbv( &op->ora_e->e_name, &op->o_req_dn );
147 	ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn );
148 
149 	Statslog( LDAP_DEBUG_STATS, "%s ADD dn=\"%s\"\n",
150 	    op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 );
151 
152 	if ( modlist == NULL ) {
153 		send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR,
154 			"no attributes provided" );
155 		goto done;
156 	}
157 
158 	if ( dn_match( &op->ora_e->e_nname, &slap_empty_bv ) ) {
159 		/* protocolError may be a more appropriate error */
160 		send_ldap_error( op, rs, LDAP_ALREADY_EXISTS,
161 			"root DSE already exists" );
162 		goto done;
163 
164 	} else if ( dn_match( &op->ora_e->e_nname, &frontendDB->be_schemandn ) ) {
165 		send_ldap_error( op, rs, LDAP_ALREADY_EXISTS,
166 			"subschema subentry already exists" );
167 		goto done;
168 	}
169 
170 	rs->sr_err = slap_mods_check( op, modlist, &rs->sr_text,
171 		textbuf, textlen, NULL );
172 
173 	if ( rs->sr_err != LDAP_SUCCESS ) {
174 		send_ldap_result( op, rs );
175 		goto done;
176 	}
177 
178 	/* temporary; remove if not invoking backend function */
179 	op->ora_modlist = modlist;
180 
181 	/* call this so global overlays/SLAPI have access to ora_e */
182 	rs->sr_err = slap_mods2entry( op->ora_modlist, &op->ora_e,
183 		1, 0, &rs->sr_text, textbuf, textlen );
184 	if ( rs->sr_err != LDAP_SUCCESS ) {
185 		send_ldap_result( op, rs );
186 		goto done;
187 	}
188 
189 	freevals = 0;
190 
191 	oex.oe.oe_key = (void *)do_add;
192 	oex.oe_db = NULL;
193 	LDAP_SLIST_INSERT_HEAD(&op->o_extra, &oex.oe, oe_next);
194 
195 	op->o_bd = frontendDB;
196 	rc = frontendDB->be_add( op, rs );
197 	LDAP_SLIST_REMOVE(&op->o_extra, &oex.oe, OpExtra, oe_next);
198 
199 #ifdef LDAP_X_TXN
200 	if ( rc == LDAP_X_TXN_SPECIFY_OKAY ) {
201 		/* skip cleanup */
202 		return rc;
203 	} else
204 #endif
205 	if ( rc == 0 ) {
206 		if ( op->ora_e != NULL && oex.oe_db != NULL ) {
207 			BackendDB	*bd = op->o_bd;
208 
209 			op->o_bd = oex.oe_db;
210 
211 			be_entry_release_w( op, op->ora_e );
212 
213 			op->ora_e = NULL;
214 			op->o_bd = bd;
215 		}
216 	}
217 
218 done:;
219 	if ( modlist != NULL ) {
220 		/* in case of error, free the values as well */
221 		slap_mods_free( modlist, freevals );
222 	}
223 
224 	if ( op->ora_e != NULL ) {
225 		entry_free( op->ora_e );
226 	}
227 	op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
228 	op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
229 
230 	return rc;
231 }
232 
233 int
234 fe_op_add( Operation *op, SlapReply *rs )
235 {
236 	Modifications	**modtail = &op->ora_modlist;
237 	int		rc = 0;
238 	BackendDB	*op_be, *bd = op->o_bd;
239 	char		textbuf[ SLAP_TEXT_BUFLEN ];
240 	size_t		textlen = sizeof( textbuf );
241 
242 	/*
243 	 * We could be serving multiple database backends.  Select the
244 	 * appropriate one, or send a referral to our "referral server"
245 	 * if we don't hold it.
246 	 */
247 	op->o_bd = select_backend( &op->ora_e->e_nname, 1 );
248 	if ( op->o_bd == NULL ) {
249 		op->o_bd = bd;
250 		rs->sr_ref = referral_rewrite( default_referral,
251 			NULL, &op->ora_e->e_name, LDAP_SCOPE_DEFAULT );
252 		if ( !rs->sr_ref ) rs->sr_ref = default_referral;
253 		if ( rs->sr_ref ) {
254 			rs->sr_err = LDAP_REFERRAL;
255 			send_ldap_result( op, rs );
256 
257 			if ( rs->sr_ref != default_referral ) {
258 				ber_bvarray_free( rs->sr_ref );
259 			}
260 		} else {
261 			send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
262 				"no global superior knowledge" );
263 		}
264 		goto done;
265 	}
266 
267 	/* If we've got a glued backend, check the real backend */
268 	op_be = op->o_bd;
269 	if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
270 		op->o_bd = select_backend( &op->ora_e->e_nname, 0 );
271 	}
272 
273 	/* check restrictions */
274 	if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
275 		send_ldap_result( op, rs );
276 		goto done;
277 	}
278 
279 	/* check for referrals */
280 	if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
281 		goto done;
282 	}
283 
284 	rs->sr_err = slap_mods_obsolete_check( op, op->ora_modlist,
285 		&rs->sr_text, textbuf, textlen );
286 
287 	if ( rs->sr_err != LDAP_SUCCESS ) {
288 		send_ldap_result( op, rs );
289 		goto done;
290 	}
291 
292 	/*
293 	 * do the add if 1 && (2 || 3)
294 	 * 1) there is an add function implemented in this backend;
295 	 * 2) this backend is master for what it holds;
296 	 * 3) it's a replica and the dn supplied is the updatedn.
297 	 */
298 	if ( op->o_bd->be_add ) {
299 		/* do the update here */
300 		int repl_user = be_isupdate( op );
301 		if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) {
302 			int		update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
303 
304 			op->o_bd = op_be;
305 
306 			if ( !update ) {
307 				rs->sr_err = slap_mods_no_user_mod_check( op, op->ora_modlist,
308 					&rs->sr_text, textbuf, textlen );
309 
310 				if ( rs->sr_err != LDAP_SUCCESS ) {
311 					send_ldap_result( op, rs );
312 					goto done;
313 				}
314 			}
315 
316 			if ( !repl_user ) {
317 				/* go to the last mod */
318 				for ( modtail = &op->ora_modlist;
319 						*modtail != NULL;
320 						modtail = &(*modtail)->sml_next )
321 				{
322 					assert( (*modtail)->sml_op == LDAP_MOD_ADD );
323 					assert( (*modtail)->sml_desc != NULL );
324 				}
325 
326 
327 				/* check for unmodifiable attributes */
328 				rs->sr_err = slap_mods_no_repl_user_mod_check( op,
329 					op->ora_modlist, &rs->sr_text, textbuf, textlen );
330 				if ( rs->sr_err != LDAP_SUCCESS ) {
331 					send_ldap_result( op, rs );
332 					goto done;
333 				}
334 			}
335 
336 			rc = op->o_bd->be_add( op, rs );
337 			if ( rc == LDAP_SUCCESS ) {
338 				OpExtra *oex;
339 				/* NOTE: be_entry_release_w() is
340 				 * called by do_add(), so that global
341 				 * overlays on the way back can
342 				 * at least read the entry */
343 				LDAP_SLIST_FOREACH(oex, &op->o_extra, oe_next) {
344 					if ( oex->oe_key == (void *)do_add ) {
345 						((OpExtraDB *)oex)->oe_db = op->o_bd;
346 						break;
347 					}
348 				}
349 			}
350 
351 		} else {
352 			BerVarray defref = NULL;
353 
354 			defref = op->o_bd->be_update_refs
355 				? op->o_bd->be_update_refs : default_referral;
356 
357 			if ( defref != NULL ) {
358 				rs->sr_ref = referral_rewrite( defref,
359 					NULL, &op->ora_e->e_name, LDAP_SCOPE_DEFAULT );
360 				if ( rs->sr_ref == NULL ) rs->sr_ref = defref;
361 				rs->sr_err = LDAP_REFERRAL;
362 				if (!rs->sr_ref) rs->sr_ref = default_referral;
363 				send_ldap_result( op, rs );
364 
365 				if ( rs->sr_ref != default_referral ) {
366 					ber_bvarray_free( rs->sr_ref );
367 				}
368 			} else {
369 				send_ldap_error( op, rs,
370 					LDAP_UNWILLING_TO_PERFORM,
371 					"shadow context; no update referral" );
372 			}
373 		}
374 	} else {
375 		Debug( LDAP_DEBUG_ARGS, "do_add: no backend support\n", 0, 0, 0 );
376 		send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
377 			"operation not supported within namingContext" );
378 	}
379 
380 done:;
381 	op->o_bd = bd;
382 	return rc;
383 }
384 
385 int
386 slap_mods2entry(
387 	Modifications *mods,
388 	Entry **e,
389 	int initial,
390 	int dup,
391 	const char **text,
392 	char *textbuf, size_t textlen )
393 {
394 	Attribute **tail;
395 	int i;
396 
397 	if ( initial ) {
398 		assert( (*e)->e_attrs == NULL );
399 	}
400 
401 	for ( tail = &(*e)->e_attrs; *tail != NULL; tail = &(*tail)->a_next )
402 		;
403 
404 	*text = textbuf;
405 
406 	for( ; mods != NULL; mods = mods->sml_next ) {
407 		Attribute *attr;
408 
409 		assert( mods->sml_desc != NULL );
410 
411 		attr = attr_find( (*e)->e_attrs, mods->sml_desc );
412 
413 		if( attr != NULL ) {
414 #define SLURPD_FRIENDLY
415 #ifdef SLURPD_FRIENDLY
416 			int j;
417 
418 			if ( !initial ) {
419 				/*
420 				 * This check allows overlays to override operational
421 				 * attributes by setting them directly in the entry.
422 				 * We assume slap_mods_no_user_mod_check() was called
423 				 * with the user modifications.
424 				 */
425 				*text = NULL;
426 				return LDAP_SUCCESS;
427 			}
428 
429 			i = attr->a_numvals;
430 			j = mods->sml_numvals;
431 			attr->a_numvals += j;
432 			j++;	/* NULL */
433 
434 			attr->a_vals = ch_realloc( attr->a_vals,
435 				sizeof( struct berval ) * (i+j) );
436 
437 			/* checked for duplicates in slap_mods_check */
438 
439 			if ( dup ) {
440 				for ( j = 0; mods->sml_values[j].bv_val; j++ ) {
441 					ber_dupbv( &attr->a_vals[i+j], &mods->sml_values[j] );
442 				}
443 				BER_BVZERO( &attr->a_vals[i+j] );
444 				j++;
445 			} else {
446 				AC_MEMCPY( &attr->a_vals[i], mods->sml_values,
447 					sizeof( struct berval ) * j );
448 			}
449 
450 			if( mods->sml_nvalues ) {
451 				attr->a_nvals = ch_realloc( attr->a_nvals,
452 					sizeof( struct berval ) * (i+j) );
453 				if ( dup ) {
454 					for ( j = 0; mods->sml_nvalues[j].bv_val; j++ ) {
455 						ber_dupbv( &attr->a_nvals[i+j], &mods->sml_nvalues[j] );
456 					}
457 					BER_BVZERO( &attr->a_nvals[i+j] );
458 				} else {
459 					AC_MEMCPY( &attr->a_nvals[i], mods->sml_nvalues,
460 						sizeof( struct berval ) * j );
461 				}
462 			} else {
463 				attr->a_nvals = attr->a_vals;
464 			}
465 
466 			continue;
467 #else
468 			snprintf( textbuf, textlen,
469 				"attribute '%s' provided more than once",
470 				mods->sml_desc->ad_cname.bv_val );
471 			*text = textbuf;
472 			return LDAP_TYPE_OR_VALUE_EXISTS;
473 #endif
474 		}
475 
476 		attr = attr_alloc( mods->sml_desc );
477 
478 		/* move values to attr structure */
479 		i = mods->sml_numvals;
480 		attr->a_numvals = mods->sml_numvals;
481 		if ( dup ) {
482 			attr->a_vals = (BerVarray) ch_calloc( i+1, sizeof( BerValue ));
483 			for ( i = 0; mods->sml_values[i].bv_val; i++ ) {
484 				ber_dupbv( &attr->a_vals[i], &mods->sml_values[i] );
485 			}
486 			BER_BVZERO( &attr->a_vals[i] );
487 		} else {
488 			attr->a_vals = mods->sml_values;
489 		}
490 
491 		if ( mods->sml_nvalues ) {
492 			if ( dup ) {
493 				i = mods->sml_numvals;
494 				attr->a_nvals = (BerVarray) ch_calloc( i+1, sizeof( BerValue ));
495 				for ( i = 0; mods->sml_nvalues[i].bv_val; i++ ) {
496 					ber_dupbv( &attr->a_nvals[i], &mods->sml_nvalues[i] );
497 				}
498 				BER_BVZERO( &attr->a_nvals[i] );
499 			} else {
500 				attr->a_nvals = mods->sml_nvalues;
501 			}
502 		} else {
503 			attr->a_nvals = attr->a_vals;
504 		}
505 
506 		*tail = attr;
507 		tail = &attr->a_next;
508 	}
509 
510 	*text = NULL;
511 
512 	return LDAP_SUCCESS;
513 }
514 
515 int
516 slap_entry2mods(
517 	Entry *e,
518 	Modifications **mods,
519 	const char **text,
520 	char *textbuf, size_t textlen )
521 {
522 	Modifications	*modhead = NULL;
523 	Modifications	*mod;
524 	Modifications	**modtail = &modhead;
525 	Attribute		*a_new;
526 	AttributeDescription	*a_new_desc;
527 	int				i, count;
528 
529 	a_new = e->e_attrs;
530 
531 	while ( a_new != NULL ) {
532 		a_new_desc = a_new->a_desc;
533 		mod = (Modifications *) ch_malloc( sizeof( Modifications ));
534 
535 		mod->sml_op = LDAP_MOD_REPLACE;
536 		mod->sml_flags = 0;
537 
538 		mod->sml_type = a_new_desc->ad_cname;
539 
540 		count = a_new->a_numvals;
541 		mod->sml_numvals = a_new->a_numvals;
542 
543 		mod->sml_values = (struct berval*) ch_malloc(
544 			(count+1) * sizeof( struct berval) );
545 
546 		/* see slap_mods_check() comments...
547 		 * if a_vals == a_nvals, there is no normalizer.
548 		 * in this case, mod->sml_nvalues must be left NULL.
549 		 */
550 		if ( a_new->a_vals != a_new->a_nvals ) {
551 			mod->sml_nvalues = (struct berval*) ch_malloc(
552 				(count+1) * sizeof( struct berval) );
553 		} else {
554 			mod->sml_nvalues = NULL;
555 		}
556 
557 		for ( i = 0; i < count; i++ ) {
558 			ber_dupbv(mod->sml_values+i, a_new->a_vals+i);
559 			if ( mod->sml_nvalues ) {
560 				ber_dupbv( mod->sml_nvalues+i, a_new->a_nvals+i );
561 			}
562 		}
563 
564 		mod->sml_values[count].bv_val = NULL;
565 		mod->sml_values[count].bv_len = 0;
566 
567 		if ( mod->sml_nvalues ) {
568 			mod->sml_nvalues[count].bv_val = NULL;
569 			mod->sml_nvalues[count].bv_len = 0;
570 		}
571 
572 		mod->sml_desc = a_new_desc;
573 		mod->sml_next =NULL;
574 		*modtail = mod;
575 		modtail = &mod->sml_next;
576 		a_new = a_new->a_next;
577 	}
578 
579 	*mods = modhead;
580 
581 	return LDAP_SUCCESS;
582 }
583 
584 int slap_add_opattrs(
585 	Operation *op,
586 	const char **text,
587 	char *textbuf,
588 	size_t textlen,
589 	int manage_ctxcsn )
590 {
591 	struct berval name, timestamp, csn = BER_BVNULL;
592 	struct berval nname, tmp;
593 	char timebuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
594 	char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
595 	Attribute *a;
596 
597 	if ( SLAP_LASTMOD( op->o_bd ) ) {
598 		char *ptr;
599 		int gotcsn = 0;
600 
601 		timestamp.bv_val = timebuf;
602 		a = attr_find( op->ora_e->e_attrs, slap_schema.si_ad_entryCSN );
603 		if ( a ) {
604 			gotcsn = 1;
605 			csn = a->a_vals[0];
606 		}
607 		if ( BER_BVISEMPTY( &op->o_csn )) {
608 			if ( !gotcsn ) {
609 				csn.bv_val = csnbuf;
610 				csn.bv_len = sizeof(csnbuf);
611 				slap_get_csn( op, &csn, manage_ctxcsn );
612 			} else {
613 				if ( manage_ctxcsn )
614 					slap_queue_csn( op, &csn );
615 			}
616 		} else {
617 			csn = op->o_csn;
618 		}
619 		ptr = ber_bvchr( &csn, '#' );
620 		if ( ptr ) {
621 			timestamp.bv_len = STRLENOF("YYYYMMDDHHMMSSZ");
622 			AC_MEMCPY( timebuf, csn.bv_val, timestamp.bv_len );
623 			timebuf[timestamp.bv_len-1] = 'Z';
624 			timebuf[timestamp.bv_len] = '\0';
625 		} else {
626 			time_t now = slap_get_time();
627 
628 			timestamp.bv_len = sizeof(timebuf);
629 
630 			slap_timestamp( &now, &timestamp );
631 		}
632 
633 		if ( BER_BVISEMPTY( &op->o_dn ) ) {
634 			BER_BVSTR( &name, SLAPD_ANONYMOUS );
635 			nname = name;
636 		} else {
637 			name = op->o_dn;
638 			nname = op->o_ndn;
639 		}
640 
641 		a = attr_find( op->ora_e->e_attrs,
642 			slap_schema.si_ad_entryUUID );
643 		if ( !a ) {
644 			char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
645 
646 			tmp.bv_len = lutil_uuidstr( uuidbuf, sizeof( uuidbuf ) );
647 			tmp.bv_val = uuidbuf;
648 
649 			attr_merge_normalize_one( op->ora_e,
650 				slap_schema.si_ad_entryUUID, &tmp, op->o_tmpmemctx );
651 		}
652 
653 		a = attr_find( op->ora_e->e_attrs,
654 			slap_schema.si_ad_creatorsName );
655 		if ( !a ) {
656 			attr_merge_one( op->ora_e,
657 				slap_schema.si_ad_creatorsName, &name, &nname );
658 		}
659 
660 		a = attr_find( op->ora_e->e_attrs,
661 			slap_schema.si_ad_createTimestamp );
662 		if ( !a ) {
663 			attr_merge_one( op->ora_e,
664 				slap_schema.si_ad_createTimestamp, &timestamp, NULL );
665 		}
666 
667 		if ( !gotcsn ) {
668 			attr_merge_one( op->ora_e,
669 				slap_schema.si_ad_entryCSN, &csn, NULL );
670 		}
671 
672 		a = attr_find( op->ora_e->e_attrs,
673 			slap_schema.si_ad_modifiersName );
674 		if ( !a ) {
675 			attr_merge_one( op->ora_e,
676 				slap_schema.si_ad_modifiersName, &name, &nname );
677 		}
678 
679 		a = attr_find( op->ora_e->e_attrs,
680 			slap_schema.si_ad_modifyTimestamp );
681 		if ( !a ) {
682 			attr_merge_one( op->ora_e,
683 				slap_schema.si_ad_modifyTimestamp, &timestamp, NULL );
684 		}
685 	}
686 
687 	return LDAP_SUCCESS;
688 }
689