]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/add.c
Proxy caching update : op->o_caching_on flag removed
[openldap] / servers / slapd / back-ldbm / add.c
1 /* add.c - ldap ldbm back-end add routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/string.h>
14
15 #include "slap.h"
16 #include "back-ldbm.h"
17 #include "proto-back-ldbm.h"
18
19 int
20 ldbm_back_add(
21     Operation   *op,
22     SlapReply   *rs )
23 {
24         struct ldbminfo *li = (struct ldbminfo *) op->o_bd->be_private;
25         struct berval   pdn;
26         Entry           *p = NULL;
27         ID               id = NOID;
28         AttributeDescription *children = slap_schema.si_ad_children;
29         AttributeDescription *entry = slap_schema.si_ad_entry;
30         char textbuf[SLAP_TEXT_BUFLEN];
31         size_t textlen = sizeof textbuf;
32 #ifdef LDBM_SUBENTRIES
33         int subentry;
34 #endif
35
36 #ifdef NEW_LOGGING
37         LDAP_LOG( BACK_LDBM, ENTRY, "ldbm_back_add: %s\n", op->o_req_dn.bv_val, 0, 0 );
38 #else
39         Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", op->o_req_dn.bv_val, 0, 0);
40 #endif
41         
42         rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e, NULL, &rs->sr_text, textbuf, textlen );
43
44         if ( rs->sr_err != LDAP_SUCCESS ) {
45 #ifdef NEW_LOGGING
46                 LDAP_LOG( BACK_LDBM, ERR, 
47                         "ldbm_back_add: entry (%s) failed schema check.\n", op->o_req_dn.bv_val, 0, 0 );
48 #else
49                 Debug( LDAP_DEBUG_TRACE, "entry failed schema check: %s\n",
50                         rs->sr_text, 0, 0 );
51 #endif
52
53                 send_ldap_result( op, rs );
54 #ifdef LDAP_SYNCREPL
55                 return rs->sr_err;
56 #else
57                 return( -1 );
58 #endif
59         }
60
61 #ifdef LDBM_SUBENTRIES
62         subentry = is_entry_subentry( op->oq_add.rs_e );
63 #endif
64
65         if ( !access_allowed( op, op->oq_add.rs_e,
66                                 entry, NULL, ACL_WRITE, NULL ) )
67         {
68 #ifdef NEW_LOGGING
69                 LDAP_LOG( BACK_LDBM, ERR, 
70                         "ldbm_back_add: No write access to entry (%s).\n", 
71                         op->o_req_dn.bv_val, 0, 0 );
72 #else
73                 Debug( LDAP_DEBUG_TRACE, "no write access to entry\n", 0,
74                     0, 0 );
75 #endif
76
77                 send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
78                     "no write access to entry" );
79
80 #ifdef LDAP_SYNCREPL
81                 return LDAP_INSUFFICIENT_ACCESS;
82 #else
83                 return -1;
84 #endif
85         }
86
87         /* grab giant lock for writing */
88         ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
89
90         if ( ( rs->sr_err = dn2id( op->o_bd, &op->o_req_ndn, &id ) ) || id != NOID ) {
91                 /* if (rs->sr_err) something bad happened to ldbm cache */
92                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
93                 rs->sr_err = rs->sr_err ? LDAP_OTHER : LDAP_ALREADY_EXISTS;
94                 send_ldap_result( op, rs );
95 #ifdef LDAP_SYNCREPL
96                 return rs->sr_err;
97 #else
98                 return( -1 );
99 #endif
100         }
101
102         /*
103          * Get the parent dn and see if the corresponding entry exists.
104          * If the parent does not exist, only allow the "root" user to
105          * add the entry.
106          */
107
108         if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
109                 pdn = slap_empty_bv;
110         } else {
111                 dnParent( &op->o_req_ndn, &pdn );
112         }
113
114         if( pdn.bv_len )
115         {
116                 Entry *matched = NULL;
117
118                 /* get parent with writer lock */
119                 if ( (p = dn2entry_w( op->o_bd, &pdn, &matched )) == NULL ) {
120                         if ( matched != NULL ) {
121                                 rs->sr_matched = ch_strdup( matched->e_dn );
122                                 rs->sr_ref = is_entry_referral( matched )
123                                         ? get_entry_referrals( op, matched )
124                                         : NULL;
125                                 cache_return_entry_r( &li->li_cache, matched );
126
127                         } else {
128                                 rs->sr_ref = referral_rewrite( default_referral,
129                                         NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
130                         }
131
132                         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
133
134 #ifdef NEW_LOGGING
135                         LDAP_LOG( BACK_LDBM, ERR, 
136                                 "ldbm_back_add: Parent of (%s) does not exist.\n", 
137                                 op->o_req_dn.bv_val, 0, 0 );
138 #else
139                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
140                                 0, 0, 0 );
141 #endif
142
143                         rs->sr_text = rs->sr_ref ? "parent is referral" : "parent does not exist";
144                         rs->sr_err = LDAP_REFERRAL;
145                         send_ldap_result( op, rs );
146
147                         ber_bvarray_free( rs->sr_ref );
148                         free( (char *)rs->sr_matched );
149
150 #ifdef LDAP_SYNCREPL
151                         return rs->sr_err;
152 #else
153                         return -1;
154 #endif
155                 }
156
157                 if ( ! access_allowed( op, p,
158                         children, NULL, ACL_WRITE, NULL ) )
159                 {
160                         /* free parent and writer lock */
161                         cache_return_entry_w( &li->li_cache, p ); 
162                         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
163
164 #ifdef NEW_LOGGING
165                         LDAP_LOG( BACK_LDBM, ERR, 
166                                 "ldbm_back_add: No write access to parent (%s).\n", 
167                                 op->o_req_dn.bv_val, 0, 0 );
168 #else
169                         Debug( LDAP_DEBUG_TRACE, "no write access to parent\n", 0,
170                             0, 0 );
171 #endif
172
173                         send_ldap_error( op, rs, LDAP_INSUFFICIENT_ACCESS,
174                             "no write access to parent" );
175
176 #ifdef LDAP_SYNCREPL
177                         return LDAP_INSUFFICIENT_ACCESS;
178 #else
179                         return -1;
180 #endif
181                 }
182
183 #ifdef LDBM_SUBENTRIES
184                 if ( is_entry_subentry( p )) {
185 #ifdef NEW_LOGGING
186                         LDAP_LOG( OPERATION, DETAIL1,
187                                 "bdb_add: parent is subentry\n", 0, 0, 0 );
188 #else
189                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is subentry\n",
190                                 0, 0, 0 );
191 #endif
192                         rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
193                         rs->sr_text = "parent is a subentry";
194                         goto return_results;
195                 }
196 #endif
197
198                 if ( is_entry_alias( p ) ) {
199                         /* parent is an alias, don't allow add */
200
201                         /* free parent and writer lock */
202                         cache_return_entry_w( &li->li_cache, p );
203                         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
204
205 #ifdef NEW_LOGGING
206                         LDAP_LOG(BACK_LDBM, ERR, 
207                                 "ldbm_back_add:  Parent is an alias.\n", 0, 0, 0 );
208 #else
209                         Debug( LDAP_DEBUG_TRACE, "parent is alias\n", 0,
210                             0, 0 );
211 #endif
212
213
214                         send_ldap_error( op, rs, LDAP_ALIAS_PROBLEM,
215                             "parent is an alias" );
216
217 #ifdef LDAP_SYNCREPL
218                         return LDAP_ALIAS_PROBLEM;
219 #else
220                         return -1;
221 #endif
222                 }
223
224                 if ( is_entry_referral( p ) ) {
225                         /* parent is a referral, don't allow add */
226                         rs->sr_matched = ch_strdup( p->e_dn );
227                         rs->sr_ref = is_entry_referral( p )
228                                 ? get_entry_referrals( op, p )
229                                 : NULL;
230
231                         /* free parent and writer lock */
232                         cache_return_entry_w( &li->li_cache, p );
233                         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
234
235 #ifdef NEW_LOGGING
236                         LDAP_LOG( BACK_LDBM, ERR,
237                                    "ldbm_back_add: Parent is referral.\n", 0, 0, 0 );
238 #else
239                         Debug( LDAP_DEBUG_TRACE, "parent is referral\n", 0,
240                             0, 0 );
241 #endif
242                         rs->sr_err = LDAP_REFERRAL;
243                         send_ldap_result( op, rs );
244
245                         ber_bvarray_free( rs->sr_ref );
246                         free( (char *)rs->sr_matched );
247 #ifdef LDAP_SYNCREPL
248                         return rs->sr_err;
249 #else
250                         return -1;
251 #endif
252                 }
253
254 #ifdef LDBM_SUBENTRIES
255                 if ( subentry ) {
256                         /* FIXME: */
257                         /* parent must be an administrative point of the required kind */
258                 }
259 #endif
260
261         } else {
262                 if( pdn.bv_val != NULL )
263                 {
264                         assert( *pdn.bv_val == '\0' );
265                 }
266
267                 /* no parent, must be adding entry to root */
268                 if ( !be_isroot( op->o_bd, &op->o_ndn ) )
269                 {
270                         if ( be_issuffix( op->o_bd, (struct berval *)&slap_empty_bv ) || be_isupdate( op->o_bd, &op->o_ndn ) ) {
271                                 p = (Entry *)&slap_entry_root;
272                                 
273                                 rs->sr_err = access_allowed( op, p,
274                                         children, NULL, ACL_WRITE, NULL );
275                                 p = NULL;
276                                 
277                                 if ( ! rs->sr_err ) {
278                                         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
279
280 #ifdef NEW_LOGGING
281                                         LDAP_LOG( BACK_LDBM, ERR,
282                                                 "ldbm_back_add: No write "
283                                                 "access to parent (\"\").\n", 0, 0, 0 );
284 #else
285                                         Debug( LDAP_DEBUG_TRACE, 
286                                                 "no write access to parent\n", 
287                                                 0, 0, 0 );
288 #endif
289
290                                         send_ldap_error( op, rs,
291                                                 LDAP_INSUFFICIENT_ACCESS,
292                                                 "no write access to parent" );
293
294 #ifdef LDAP_SYNCREPL
295                                         return LDAP_INSUFFICIENT_ACCESS;
296 #else
297                                         return -1;
298 #endif
299                                 }
300 #ifdef LDAP_SYNCREPL
301                         } else if ( !is_entry_glue( op->oq_add.rs_e )) {
302 #else
303                         } else {
304 #endif
305                                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
306
307 #ifdef NEW_LOGGING
308                                 LDAP_LOG( BACK_LDBM, ERR,
309                                            "ldbm_back_add: %s add denied.\n",
310                                            pdn.bv_val == NULL ? "suffix" 
311                                            : "entry at root", 0, 0 );
312 #else
313                                 Debug( LDAP_DEBUG_TRACE, "%s add denied\n",
314                                                 pdn.bv_val == NULL ? "suffix" 
315                                                 : "entry at root", 0, 0 );
316 #endif
317
318                                 send_ldap_error( op, rs,
319                                                 LDAP_NO_SUCH_OBJECT, NULL );
320
321 #ifdef LDAP_SYNCREPL
322                                         return LDAP_NO_SUCH_OBJECT;
323 #else
324                                         return -1;
325 #endif
326                         }
327                 }
328
329 #ifdef LDBM_SUBENTRIES
330                         if( subentry ) {
331 #ifdef NEW_LOGGING
332                                         LDAP_LOG ( OPERATION, DETAIL1,
333                                                 "bdb_add: no parent, cannot add subentry\n", 0, 0, 0 );
334 #else
335                                         Debug( LDAP_DEBUG_TRACE,
336                                                 "bdb_add: no parent, cannot add subentry\n", 0, 0, 0 );
337 #endif
338                                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
339                                         rs->sr_text = "no parent, cannot add subentry";
340                                         goto return_results;
341                                 }
342 #endif
343
344         }
345
346         if ( next_id( op->o_bd, &op->oq_add.rs_e->e_id ) ) {
347                 if( p != NULL) {
348                         /* free parent and writer lock */
349                         cache_return_entry_w( &li->li_cache, p ); 
350                 }
351
352                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
353
354 #ifdef NEW_LOGGING
355                 LDAP_LOG( BACK_LDBM, ERR,
356                         "ldbm_back_add: next_id failed.\n", 0, 0, 0 );
357 #else
358                 Debug( LDAP_DEBUG_ANY, "ldbm_add: next_id failed\n",
359                         0, 0, 0 );
360 #endif
361
362                 send_ldap_error( op, rs, LDAP_OTHER,
363                         "next_id add failed" );
364
365 #ifdef LDAP_SYNCREPL
366                 return LDAP_OTHER;
367 #else
368                 return( -1 );
369 #endif
370         }
371
372         /*
373          * Try to add the entry to the cache, assign it a new dnid.
374          */
375         rs->sr_err = cache_add_entry_rw(&li->li_cache, op->oq_add.rs_e, CACHE_WRITE_LOCK);
376
377         if ( rs->sr_err != 0 ) {
378                 if( p != NULL) {
379                         /* free parent and writer lock */
380                         cache_return_entry_w( &li->li_cache, p ); 
381                 }
382
383                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
384
385 #ifdef NEW_LOGGING
386                 LDAP_LOG( BACK_LDBM, ERR,
387                         "ldbm_back_add: cache_add_entry_lock failed.\n", 0, 0, 0 );
388 #else
389                 Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
390                     0 );
391 #endif
392
393                 rs->sr_text = rs->sr_err > 0 ? NULL : "cache add failed";
394                 rs->sr_err = rs->sr_err > 0 ? LDAP_ALREADY_EXISTS : LDAP_OTHER;
395                 send_ldap_result( op, rs );
396
397 #ifdef LDAP_SYNCREPL
398                 return rs->sr_err;
399 #else
400                 return( -1 );
401 #endif
402         }
403
404         rs->sr_err = -1;
405
406         /* attribute indexes */
407         if ( index_entry_add( op, op->oq_add.rs_e ) != LDAP_SUCCESS ) {
408 #ifdef NEW_LOGGING
409                 LDAP_LOG( BACK_LDBM, ERR,
410                         "ldbm_back_add: index_entry_add failed.\n", 0, 0, 0 );
411 #else
412                 Debug( LDAP_DEBUG_TRACE, "index_entry_add failed\n", 0,
413                     0, 0 );
414 #endif
415                 
416                 send_ldap_error( op, rs, LDAP_OTHER,
417                         "index generation failed" );
418
419                 goto return_results;
420         }
421
422         /* dn2id index */
423         if ( dn2id_add( op->o_bd, &op->oq_add.rs_e->e_nname, op->oq_add.rs_e->e_id ) != 0 ) {
424 #ifdef NEW_LOGGING
425                 LDAP_LOG( BACK_LDBM, ERR,
426                         "ldbm_back_add: dn2id_add failed.\n", 0, 0, 0 );
427 #else
428                 Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0,
429                     0, 0 );
430 #endif
431                 /* FIXME: delete attr indices? */
432
433                 send_ldap_error( op, rs, LDAP_OTHER,
434                         "DN index generation failed" );
435
436                 goto return_results;
437         }
438
439         /* id2entry index */
440         if ( id2entry_add( op->o_bd, op->oq_add.rs_e ) != 0 ) {
441 #ifdef NEW_LOGGING
442                 LDAP_LOG( BACK_LDBM, ERR,
443                            "ldbm_back_add: id2entry_add failed.\n", 0, 0, 0 );
444 #else
445                 Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0,
446                     0, 0 );
447 #endif
448
449                 /* FIXME: delete attr indices? */
450                 (void) dn2id_delete( op->o_bd, &op->oq_add.rs_e->e_nname, op->oq_add.rs_e->e_id );
451                 
452                 send_ldap_error( op, rs, LDAP_OTHER,
453                         "entry store failed" );
454
455                 goto return_results;
456         }
457
458         rs->sr_err = LDAP_SUCCESS;
459         send_ldap_result( op, rs );
460
461         /* marks the entry as committed, so it is added to the cache;
462          * otherwise it is removed from the cache, but not destroyed;
463          * it will be destroyed by the caller */
464         cache_entry_commit( op->oq_add.rs_e );
465
466 return_results:;
467         if (p != NULL) {
468                 /* free parent and writer lock */
469                 cache_return_entry_w( &li->li_cache, p ); 
470         }
471
472         if ( rs->sr_err ) {
473                 /*
474                  * in case of error, writer lock is freed 
475                  * and entry's private data is destroyed.
476                  * otherwise, this is done when entry is released
477                  */
478                 cache_return_entry_w( &li->li_cache, op->oq_add.rs_e );
479                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
480         }
481
482         return( rs->sr_err );
483 }