]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/add.c
Never let ldif_parse_line() return a NULL value with success.
[openldap] / servers / slapd / back-bdb / add.c
1 /* add.c - ldap BerkeleyDB back-end add routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2002 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 #include <ac/string.h>
12
13 #include "back-bdb.h"
14 #include "external.h"
15
16 int
17 bdb_add(
18         BackendDB       *be,
19         Connection      *conn,
20         Operation       *op,
21         Entry   *e )
22 {
23         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
24         struct berval   pdn;
25         Entry           *p = NULL;
26         int             rc; 
27         const char      *text;
28         char textbuf[SLAP_TEXT_BUFLEN];
29         size_t textlen = sizeof textbuf;
30         AttributeDescription *children = slap_schema.si_ad_children;
31         AttributeDescription *entry = slap_schema.si_ad_entry;
32         DB_TXN          *ltid = NULL;
33         struct bdb_op_info opinfo;
34 #ifdef BDB_SUBENTRIES
35         int subentry;
36 #endif
37         u_int32_t       locker;
38         DB_LOCK         lock;
39 #if 0
40         u_int32_t       lockid;
41         DB_LOCK         lock;
42 #endif
43         int             noop = 0;
44
45 #ifdef LDAP_CLIENT_UPDATE
46         Operation* ps_list;
47 #endif
48
49 #ifdef NEW_LOGGING
50         LDAP_LOG ( OPERATION, ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0 );
51 #else
52         Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
53 #endif
54
55         /* check entry's schema */
56         rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
57         if ( rc != LDAP_SUCCESS ) {
58 #ifdef NEW_LOGGING
59         LDAP_LOG ( OPERATION, ERR, 
60                 "bdb_add: entry failed schema check: %s (%d)\n", text, rc, 0 );
61 #else
62                 Debug( LDAP_DEBUG_TRACE,
63                         "bdb_add: entry failed schema check: %s (%d)\n",
64                         text, rc, 0 );
65 #endif
66                 goto return_results;
67         }
68
69 #ifdef BDB_SUBENTRIES
70         subentry = is_entry_subentry( e );
71 #endif
72
73         /*
74          * acquire an ID outside of the operation transaction
75          * to avoid serializing adds.
76          */
77         rc = bdb_next_id( be, NULL, &e->e_id );
78         if( rc != 0 ) {
79 #ifdef NEW_LOGGING
80                 LDAP_LOG ( OPERATION, ERR, 
81                         "bdb_add: next_id failed (%d)\n", rc, 0, 0 );
82 #else
83                 Debug( LDAP_DEBUG_TRACE,
84                         "bdb_add: next_id failed (%d)\n",
85                         rc, 0, 0 );
86 #endif
87                 rc = LDAP_OTHER;
88                 text = "internal error";
89                 goto return_results;
90         }
91
92         if( 0 ) {
93 retry:  /* transaction retry */
94                 if( p ) {
95                         /* free parent and reader lock */
96                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
97                         p = NULL;
98                 }
99                 rc = TXN_ABORT( ltid );
100                 ltid = NULL;
101                 op->o_private = NULL;
102                 if( rc != 0 ) {
103                         rc = LDAP_OTHER;
104                         text = "internal error";
105                         goto return_results;
106                 }
107                 ldap_pvt_thread_yield();
108         }
109
110         /* begin transaction */
111         rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &ltid, 
112                 bdb->bi_db_opflags );
113         text = NULL;
114         if( rc != 0 ) {
115 #ifdef NEW_LOGGING
116                 LDAP_LOG ( OPERATION, ERR, 
117                         "bdb_add: txn_begin failed: %s (%d)\n", db_strerror(rc), rc, 0 );
118 #else
119                 Debug( LDAP_DEBUG_TRACE,
120                         "bdb_add: txn_begin failed: %s (%d)\n",
121                         db_strerror(rc), rc, 0 );
122 #endif
123                 rc = LDAP_OTHER;
124                 text = "internal error";
125                 goto return_results;
126         }
127
128         locker = TXN_ID ( ltid );
129 #if 0
130         lockid = TXN_ID( ltid );
131 #endif
132
133         opinfo.boi_bdb = be;
134         opinfo.boi_txn = ltid;
135         opinfo.boi_err = 0;
136         op->o_private = &opinfo;
137         
138         /*
139          * Get the parent dn and see if the corresponding entry exists.
140          * If the parent does not exist, only allow the "root" user to
141          * add the entry.
142          */
143         if ( be_issuffix( be, &e->e_nname ) ) {
144                 pdn = slap_empty_bv;
145         } else {
146                 dnParent( &e->e_nname, &pdn );
147         }
148
149         if( pdn.bv_len != 0 ) {
150                 Entry *matched = NULL;
151
152 #if 0
153                 if ( ltid ) {
154                         DBT obj;
155                         obj.data = pdn.bv_val-1;
156                         obj.size = pdn.bv_len+1;
157                         rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj,
158                                 DB_LOCK_WRITE, &lock);
159                 }
160 #endif
161
162                 /* get parent */
163                 rc = bdb_dn2entry_r( be, ltid, &pdn, &p, &matched, 0, locker, &lock );
164
165                 switch( rc ) {
166                 case 0:
167                 case DB_NOTFOUND:
168                         break;
169                 case DB_LOCK_DEADLOCK:
170                 case DB_LOCK_NOTGRANTED:
171                         goto retry;
172                 case LDAP_BUSY:
173                         text = "ldap server busy";
174                         goto return_results;
175                 default:
176                         rc = LDAP_OTHER;
177                         text = "internal error";
178                         goto return_results;
179                 }
180
181                 if ( p == NULL ) {
182                         char *matched_dn = NULL;
183                         BerVarray refs;
184
185                         if ( matched != NULL ) {
186                                 matched_dn = ch_strdup( matched->e_dn );
187                                 refs = is_entry_referral( matched )
188                                         ? get_entry_referrals( be, conn, op, matched )
189                                         : NULL;
190                                 bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, matched );
191                                 matched = NULL;
192
193                         } else {
194                                 refs = referral_rewrite( default_referral,
195                                         NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
196                         }
197
198 #ifdef NEW_LOGGING
199                         LDAP_LOG ( OPERATION, DETAIL1, 
200                                 "bdb_add: parent does not exist\n", 0, 0, 0 );
201 #else
202                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n",
203                                 0, 0, 0 );
204 #endif
205
206                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
207                                 matched_dn, NULL, refs, NULL );
208
209                         ber_bvarray_free( refs );
210                         ch_free( matched_dn );
211
212                         goto done;
213                 }
214
215                 rc = access_allowed( be, conn, op, p,
216                         children, NULL, ACL_WRITE, NULL );
217
218                 switch( opinfo.boi_err ) {
219                 case DB_LOCK_DEADLOCK:
220                 case DB_LOCK_NOTGRANTED:
221                         goto retry;
222                 }
223
224                 if ( ! rc ) {
225 #ifdef NEW_LOGGING
226                         LDAP_LOG ( OPERATION, DETAIL1, 
227                                 "bdb_add: no write access to parent\n", 0, 0, 0 );
228 #else
229                         Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n",
230                                 0, 0, 0 );
231 #endif
232                         rc = LDAP_INSUFFICIENT_ACCESS;
233                         text = "no write access to parent";
234                         goto return_results;;
235                 }
236
237 #ifdef BDB_SUBENTRIES
238                 if ( is_entry_subentry( p ) ) {
239                         /* parent is a subentry, don't allow add */
240 #ifdef NEW_LOGGING
241                         LDAP_LOG ( OPERATION, DETAIL1, 
242                                 "bdb_add: parent is subentry\n", 0, 0, 0 );
243 #else
244                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is subentry\n",
245                                 0, 0, 0 );
246 #endif
247                         rc = LDAP_OBJECT_CLASS_VIOLATION;
248                         text = "parent is a subentry";
249                         goto return_results;;
250                 }
251 #endif
252 #ifdef BDB_ALIASES
253                 if ( is_entry_alias( p ) ) {
254                         /* parent is an alias, don't allow add */
255 #ifdef NEW_LOGGING
256                         LDAP_LOG ( OPERATION, DETAIL1, 
257                                 "bdb_add: parent is alias\n", 0, 0, 0 );
258 #else
259                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n",
260                                 0, 0, 0 );
261 #endif
262                         rc = LDAP_ALIAS_PROBLEM;
263                         text = "parent is an alias";
264                         goto return_results;;
265                 }
266 #endif
267
268                 if ( is_entry_referral( p ) ) {
269                         /* parent is a referral, don't allow add */
270                         char *matched_dn = p->e_dn;
271                         BerVarray refs = get_entry_referrals( be, conn, op, p );
272
273 #ifdef NEW_LOGGING
274                         LDAP_LOG ( OPERATION, DETAIL1, 
275                                 "bdb_add: parent is referral\n", 0, 0, 0 );
276 #else
277                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
278                                 0, 0, 0 );
279 #endif
280
281                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
282                                 matched_dn, NULL, refs, NULL );
283
284                         ber_bvarray_free( refs );
285                         bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
286                         p = NULL;
287                         goto done;
288                 }
289
290 #ifdef BDB_SUBENTRIES
291                 if ( subentry ) {
292                         /* FIXME: */
293                         /* parent must be an administrative point of the required kind */
294                 }
295 #endif
296
297                 /* free parent and reader lock */
298                 bdb_unlocked_cache_return_entry_r( &bdb->bi_cache, p );
299                 p = NULL;
300
301         } else {
302                 /*
303                  * no parent!
304                  *      must be adding entry at suffix or with parent ""
305                  */
306                 if ( !be_isroot( be, &op->o_ndn )) {
307                         if ( be_issuffix( be, (struct berval *)&slap_empty_bv )
308                                 || be_isupdate( be, &op->o_ndn ) )
309                         {
310                                 p = (Entry *)&slap_entry_root;
311
312                                 /* check parent for "children" acl */
313                                 rc = access_allowed( be, conn, op, p,
314                                         children, NULL, ACL_WRITE, NULL );
315
316                                 p = NULL;
317
318                                 switch( opinfo.boi_err ) {
319                                 case DB_LOCK_DEADLOCK:
320                                 case DB_LOCK_NOTGRANTED:
321                                         goto retry;
322                                 }
323
324                                 if ( ! rc ) {
325 #ifdef NEW_LOGGING
326                                         LDAP_LOG ( OPERATION, DETAIL1, 
327                                                 "bdb_add: no write access to parent\n", 0, 0, 0 );
328 #else
329                                         Debug( LDAP_DEBUG_TRACE,
330                                                 "bdb_add: no write access to parent\n",
331                                                 0, 0, 0 );
332 #endif
333                                         rc = LDAP_INSUFFICIENT_ACCESS;
334                                         text = "no write access to parent";
335                                         goto return_results;;
336                                 }
337
338                         } else {
339 #ifdef NEW_LOGGING
340                                 LDAP_LOG ( OPERATION, DETAIL1, "bdb_add: %s denied\n", 
341                                         pdn.bv_len == 0 ? "suffix" : "entry at root", 0, 0 );
342 #else
343                                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n",
344                                         pdn.bv_len == 0 ? "suffix" : "entry at root",
345                                         0, 0 );
346 #endif
347                                 rc = LDAP_INSUFFICIENT_ACCESS;
348                                 goto return_results;
349                         }
350                 }
351
352 #ifdef BDB_SUBENTRIES
353                 if( subentry ) {
354 #ifdef NEW_LOGGING
355                         LDAP_LOG ( OPERATION, DETAIL1, 
356                                 "bdb_add: no parent, cannot add subentry\n", 0, 0, 0 );
357 #else
358                         Debug( LDAP_DEBUG_TRACE,
359                                 "bdb_add: no parent, cannot add subentry\n",
360                                 0, 0, 0 );
361 #endif
362                         rc = LDAP_INSUFFICIENT_ACCESS;
363                         text = "no parent, cannot add subentry";
364                         goto return_results;;
365                 }
366 #endif
367 #if 0
368                 if ( ltid ) {
369                         DBT obj;
370                         obj.data = ",";
371                         obj.size = 1;
372                         rc = LOCK_GET( bdb->bi_dbenv, lockid, 0, &obj,
373                                 DB_LOCK_WRITE, &lock);
374                 }
375 #endif
376         }
377
378         rc = access_allowed( be, conn, op, e,
379                 entry, NULL, ACL_WRITE, NULL );
380
381         switch( opinfo.boi_err ) {
382         case DB_LOCK_DEADLOCK:
383         case DB_LOCK_NOTGRANTED:
384                 goto retry;
385         }
386
387         if ( ! rc ) {
388 #ifdef NEW_LOGGING
389                 LDAP_LOG ( OPERATION, DETAIL1, 
390                         "bdb_add: no write access to entry\n", 0, 0, 0 );
391 #else
392                 Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to entry\n",
393                         0, 0, 0 );
394 #endif
395                 rc = LDAP_INSUFFICIENT_ACCESS;
396                 text = "no write access to entry";
397                 goto return_results;;
398         }
399
400         /* dn2id index */
401         rc = bdb_dn2id_add( be, ltid, &pdn, e );
402         if ( rc != 0 ) {
403 #ifdef NEW_LOGGING
404                 LDAP_LOG ( OPERATION, ERR, 
405                         "bdb_add: dn2id_add failed: %s (%d)\n", db_strerror(rc), rc, 0 );
406 #else
407                 Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
408                         db_strerror(rc), rc, 0 );
409 #endif
410
411                 switch( rc ) {
412                 case DB_LOCK_DEADLOCK:
413                 case DB_LOCK_NOTGRANTED:
414                         goto retry;
415                 case DB_KEYEXIST:
416                         rc = LDAP_ALREADY_EXISTS;
417                         break;
418                 default:
419                         rc = LDAP_OTHER;
420                 }
421                 goto return_results;
422         }
423
424         /* id2entry index */
425         rc = bdb_id2entry_add( be, ltid, e );
426         if ( rc != 0 ) {
427 #ifdef NEW_LOGGING
428                 LDAP_LOG ( OPERATION, ERR, "bdb_add: id2entry_add failed\n", 0, 0, 0 );
429 #else
430                 Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n",
431                         0, 0, 0 );
432 #endif
433                 switch( rc ) {
434                 case DB_LOCK_DEADLOCK:
435                 case DB_LOCK_NOTGRANTED:
436                         goto retry;
437                 default:
438                         rc = LDAP_OTHER;
439                 }
440                 text = "entry store failed";
441                 goto return_results;
442         }
443
444         /* attribute indexes */
445         rc = bdb_index_entry_add( be, ltid, e, e->e_attrs );
446         if ( rc != LDAP_SUCCESS ) {
447 #ifdef NEW_LOGGING
448                 LDAP_LOG ( OPERATION, ERR, 
449                         "bdb_add: index_entry_add failed\n", 0, 0, 0 );
450 #else
451                 Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n",
452                         0, 0, 0 );
453 #endif
454                 switch( rc ) {
455                 case DB_LOCK_DEADLOCK:
456                 case DB_LOCK_NOTGRANTED:
457                         goto retry;
458                 default:
459                         rc = LDAP_OTHER;
460                 }
461                 text = "index generation failed";
462                 goto return_results;
463         }
464
465
466         if( op->o_noop ) {
467                 if (( rc=TXN_ABORT( ltid )) != 0 ) {
468                         text = "txn_abort (no-op) failed";
469                 } else {
470                         noop = 1;
471                         rc = LDAP_SUCCESS;
472                 }
473
474         } else {
475                 char gid[DB_XIDDATASIZE];
476
477                 snprintf( gid, sizeof( gid ), "%s-%08lx-%08lx",
478                         bdb_uuid.bv_val, (long) op->o_connid, (long) op->o_opid );
479
480                 if (( rc=TXN_PREPARE( ltid, gid )) != 0 ) {
481                         text = "txn_prepare failed";
482
483                 } else {
484                         int ret = bdb_cache_add_entry_rw(bdb->bi_dbenv,
485                                         &bdb->bi_cache, e, CACHE_WRITE_LOCK,
486                                         locker, &lock);
487 #if 0
488                         if ( bdb_cache_add_entry_rw(&bdb->bi_cache,
489                                 e, CACHE_WRITE_LOCK) != 0 )
490 #endif
491                         switch ( ret ) {
492                         case 0:
493                                 break;
494                         case DB_LOCK_DEADLOCK:
495                         case DB_LOCK_NOTGRANTED:
496                                 goto retry;
497                         default:
498                                 ret = LDAP_OTHER;
499                         }
500
501                         if ( ret ) {
502                                 if(( rc=TXN_ABORT( ltid )) != 0 ) {
503                                         text = "cache add & txn_abort failed";
504                                 } else {
505                                         rc = LDAP_OTHER;
506                                         text = "cache add failed";
507                                 }
508                         } else {
509                                 if(( rc=TXN_COMMIT( ltid, 0 )) != 0 ) {
510                                         text = "txn_commit failed";
511                                 } else {
512                                         rc = LDAP_SUCCESS;
513                                 }
514                         }
515                 }
516         }
517
518         ltid = NULL;
519         op->o_private = NULL;
520
521         if (rc == LDAP_SUCCESS) {
522 #ifdef NEW_LOGGING
523                 LDAP_LOG ( OPERATION, RESULTS, 
524                         "bdb_add: added%s id=%08lx dn=\"%s\"\n", 
525                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
526 #else
527                 Debug(LDAP_DEBUG_TRACE, "bdb_add: added%s id=%08lx dn=\"%s\"\n",
528                         op->o_noop ? " (no-op)" : "", e->e_id, e->e_dn );
529 #endif
530                 text = NULL;
531                 if ( !noop ) {
532                         bdb_cache_entry_commit( e );
533                 }
534         }
535         else {
536 #ifdef NEW_LOGGING
537                 LDAP_LOG ( OPERATION, ERR, 
538                         "bdb_add: %s : %s (%d)\n",  text, db_strerror(rc), rc );
539 #else
540                 Debug( LDAP_DEBUG_TRACE, "bdb_add: %s : %s (%d)\n",
541                         text, db_strerror(rc), rc );
542 #endif
543                 rc = LDAP_OTHER;
544         }
545
546 return_results:
547         send_ldap_result( conn, op, rc,
548                 NULL, text, NULL, NULL );
549
550 #ifdef LDAP_CLIENT_UPDATE
551         if ( rc == LDAP_SUCCESS && !noop ) {
552                 LDAP_LIST_FOREACH ( ps_list, &bdb->psearch_list, link ) {
553                         bdb_psearch( be, conn, op, ps_list, e, LCUP_PSEARCH_BY_ADD );
554                 }
555         }
556 #endif /* LDAP_CLIENT_UPDATE */
557
558         if( rc == LDAP_SUCCESS && bdb->bi_txn_cp ) {
559                 ldap_pvt_thread_yield();
560                 TXN_CHECKPOINT( bdb->bi_dbenv,
561                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
562         }
563
564 done:
565
566         if( ltid != NULL ) {
567                 TXN_ABORT( ltid );
568                 op->o_private = NULL;
569         }
570
571         return ( ( rc == LDAP_SUCCESS ) ? noop : rc );
572 }
573