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