1 /* add.c - ldap ldbm back-end add routine */
4 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
12 #include <ac/socket.h>
13 #include <ac/string.h>
16 #include "back-ldbm.h"
17 #include "proto-back-ldbm.h"
27 struct ldbminfo *li = (struct ldbminfo *) be->be_private;
33 const char *text = NULL;
34 AttributeDescription *children = slap_schema.si_ad_children;
35 char textbuf[SLAP_TEXT_BUFLEN];
36 size_t textlen = sizeof textbuf;
39 LDAP_LOG(( "backend", LDAP_LEVEL_ENTRY,"ldbm_back_add: %s\n",
42 Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", e->e_dn, 0, 0);
45 /* nobody else can add until we lock our parent */
46 ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
48 if ( ( rc = dn2id( be, &e->e_nname, &id ) ) || id != NOID ) {
49 /* if (rc) something bad happened to ldbm cache */
50 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
51 send_ldap_result( conn, op,
52 rc ? LDAP_OPERATIONS_ERROR : LDAP_ALREADY_EXISTS,
53 NULL, NULL, NULL, NULL );
57 rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
59 if ( rc != LDAP_SUCCESS ) {
60 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
63 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
64 "ldbm_back_add: entry (%s) failed schema check.\n",
67 Debug( LDAP_DEBUG_TRACE, "entry failed schema check: %s\n",
72 send_ldap_result( conn, op, rc,
73 NULL, text, NULL, NULL );
78 * Get the parent dn and see if the corresponding entry exists.
79 * If the parent does not exist, only allow the "root" user to
83 pdn.bv_val = dn_parent( be, e->e_ndn );
84 if (pdn.bv_val && pdn.bv_val[0])
85 pdn.bv_len = e->e_nname.bv_len - (pdn.bv_val - e->e_ndn);
90 Entry *matched = NULL;
92 /* get parent with writer lock */
93 if ( (p = dn2entry_w( be, &pdn, &matched )) == NULL ) {
94 char *matched_dn = NULL;
97 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
99 if ( matched != NULL ) {
100 matched_dn = ch_strdup( matched->e_dn );
101 refs = is_entry_referral( matched )
102 ? get_entry_referrals( be, conn, op, matched )
104 cache_return_entry_r( &li->li_cache, matched );
107 refs = referral_rewrite( default_referral,
108 NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
112 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
113 "ldbm_back_add: Parent of (%s) does not exist.\n",
116 Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
120 send_ldap_result( conn, op, LDAP_REFERRAL, matched_dn,
121 refs == NULL ? "parent does not exist" : "parent is referral",
124 bvarray_free( refs );
130 /* don't need the add lock anymore */
131 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
133 if ( ! access_allowed( be, conn, op, p,
134 children, NULL, ACL_WRITE ) )
136 /* free parent and writer lock */
137 cache_return_entry_w( &li->li_cache, p );
140 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
141 "ldbm_back_add: No write access to parent (%s).\n",
144 Debug( LDAP_DEBUG_TRACE, "no write access to parent\n", 0,
148 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
149 NULL, "no write access to parent", NULL, NULL );
155 if ( is_entry_alias( p ) ) {
156 /* parent is an alias, don't allow add */
158 /* free parent and writer lock */
159 cache_return_entry_w( &li->li_cache, p );
162 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
163 "ldbm_back_add: Parent is an alias.\n"));
165 Debug( LDAP_DEBUG_TRACE, "parent is alias\n", 0,
170 send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM,
171 NULL, "parent is an alias", NULL, NULL );
176 if ( is_entry_referral( p ) ) {
177 /* parent is a referral, don't allow add */
178 char *matched_dn = ch_strdup( p->e_dn );
179 BVarray refs = is_entry_referral( p )
180 ? get_entry_referrals( be, conn, op, p )
183 /* free parent and writer lock */
184 cache_return_entry_w( &li->li_cache, p );
187 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
188 "ldbm_back_add: Parent is referral.\n" ));
190 Debug( LDAP_DEBUG_TRACE, "parent is referral\n", 0,
194 send_ldap_result( conn, op, LDAP_REFERRAL,
195 matched_dn, NULL, refs, NULL );
197 bvarray_free( refs );
203 if(pdn.bv_val != NULL) {
204 assert( *pdn.bv_val == '\0' );
207 /* no parent, must be adding entry to root */
208 if ( !be_isroot( be, &op->o_ndn ) ) {
209 if ( be_issuffix( be, "" ) || be_isupdate( be, &op->o_ndn ) ) {
210 p = (Entry *)&slap_entry_root;
212 rc = access_allowed( be, conn, op, p,
213 children, NULL, ACL_WRITE );
217 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
220 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
221 "ldbm_back_add: No write "
222 "access to parent (\"\").\n" ));
224 Debug( LDAP_DEBUG_TRACE,
225 "no write access to parent\n",
229 send_ldap_result( conn, op,
230 LDAP_INSUFFICIENT_ACCESS,
232 "no write access to parent",
239 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
242 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
243 "ldbm_back_add: %s add denied.\n",
244 pdn.bv_val == NULL ? "suffix"
245 : "entry at root" ));
247 Debug( LDAP_DEBUG_TRACE, "%s add denied\n",
248 pdn.bv_val == NULL ? "suffix"
249 : "entry at root", 0, 0 );
252 send_ldap_result( conn, op,
253 LDAP_INSUFFICIENT_ACCESS,
254 NULL, NULL, NULL, NULL );
261 * no parent, acquire the root write lock
262 * and release the add lock.
264 ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
266 ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
269 if ( next_id( be, &e->e_id ) ) {
271 /* free parent and writer lock */
272 cache_return_entry_w( &li->li_cache, p );
276 /* release root lock */
277 ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
281 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
282 "ldbm_back_add: next_id failed.\n" ));
284 Debug( LDAP_DEBUG_ANY, "ldbm_add: next_id failed\n",
289 send_ldap_result( conn, op, LDAP_OTHER,
290 NULL, "next_id add failed", NULL, NULL );
296 * Try to add the entry to the cache, assign it a new dnid.
298 rc = cache_add_entry_rw(&li->li_cache, e, CACHE_WRITE_LOCK);
302 /* free parent and writer lock */
303 cache_return_entry_w( &li->li_cache, p );
307 /* release root lock */
308 ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
312 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
313 "ldbm_back_add: cache_add_entry_lock failed.\n" ));
315 Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
319 send_ldap_result( conn, op,
320 rc > 0 ? LDAP_ALREADY_EXISTS : LDAP_OTHER,
321 NULL, rc > 0 ? NULL : "cache add failed", NULL, NULL );
328 /* attribute indexes */
329 if ( index_entry_add( be, e, e->e_attrs ) != LDAP_SUCCESS ) {
331 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
332 "ldbm_back_add: index_entry_add failed.\n" ));
334 Debug( LDAP_DEBUG_TRACE, "index_entry_add failed\n", 0,
338 send_ldap_result( conn, op, LDAP_OTHER,
339 NULL, "index generation failed", NULL, NULL );
345 if ( dn2id_add( be, &e->e_nname, e->e_id ) != 0 ) {
347 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
348 "ldbm_back_add: dn2id_add failed.\n" ));
350 Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0,
353 /* FIXME: delete attr indices? */
355 send_ldap_result( conn, op, LDAP_OTHER,
356 NULL, "DN index generation failed", NULL, NULL );
362 if ( id2entry_add( be, e ) != 0 ) {
364 LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
365 "ldbm_back_add: id2entry_add failed.\n" ));
367 Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0,
371 /* FIXME: delete attr indices? */
372 (void) dn2id_delete( be, &e->e_nname, e->e_id );
374 send_ldap_result( conn, op, LDAP_OTHER,
375 NULL, "entry store failed", NULL, NULL );
380 send_ldap_result( conn, op, LDAP_SUCCESS,
381 NULL, NULL, NULL, NULL );
383 /* marks the entry as committed, so it is added to the cache;
384 * otherwise it is removed from the cache, but not destroyed;
385 * it will be destroyed by the caller */
387 cache_entry_commit( e );
391 /* free parent and writer lock */
392 cache_return_entry_w( &li->li_cache, p );
396 /* release root lock */
397 ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
401 /* in case of error, writer lock is freed
402 * and entry's private data is destroyed */
403 cache_return_entry_w( &li->li_cache, e );