]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/add.c
c7c2a6ce77519010429f79312d2b87681709bfa0
[openldap] / servers / slapd / back-bdb / add.c
1 /* add.c - ldap BerkeleyDB back-end add routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 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
15 int
16 bdb_add(
17         Backend *be,
18         Connection      *conn,
19         Operation       *op,
20         Entry   *e )
21 {
22         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
23         char            *pdn = NULL;
24         Entry           *p = NULL;
25         int                     rc; 
26         const char      *text = NULL;
27         AttributeDescription *children = slap_schema.si_ad_children;
28         DB_TXN          *ltid = NULL;
29
30         Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
31
32         /* check entry's schema */
33         rc = entry_schema_check( e, NULL, &text );
34         if ( rc != LDAP_SUCCESS ) {
35                 Debug( LDAP_DEBUG_TRACE,
36                         "bdb_add: entry failed schema check: %s (%d)\n",
37                         text, rc, 0 );
38                 goto return_results;
39         }
40
41         /*
42          * acquire an ID outside of the operation transaction
43          * to avoid serializing adds.
44          */
45         rc = bdb_next_id( be, NULL, &e->e_id );
46         if( rc != 0 ) {
47                 Debug( LDAP_DEBUG_TRACE,
48                         "bdb_add: next_id failed (%d)\n",
49                         rc, 0, 0 );
50                 rc = LDAP_OTHER;
51                 text = "internal error";
52                 goto return_results;
53         }
54
55         if (0) {
56                 /* transaction retry */
57 retry:  rc = txn_abort( ltid );
58                 ltid = NULL;
59                 op->o_private = NULL;
60                 if( rc != 0 ) {
61                         rc = LDAP_OTHER;
62                         text = "internal error";
63                         goto return_results;
64                 }
65         }
66
67         /* begin transaction */
68         rc = txn_begin( bdb->bi_dbenv, NULL, &ltid, 0 );
69         if( rc != 0 ) {
70                 Debug( LDAP_DEBUG_TRACE,
71                         "bdb_add: txn_begin failed: %s (%d)\n",
72                         db_strerror(rc), rc, 0 );
73                 rc = LDAP_OTHER;
74                 text = "internal error";
75                 goto return_results;
76         }
77
78         op->o_private = ltid;
79         
80         /*
81          * Get the parent dn and see if the corresponding entry exists.
82          * If the parent does not exist, only allow the "root" user to
83          * add the entry.
84          */
85         pdn = dn_parent( be, e->e_ndn );
86
87         if( pdn != NULL && *pdn != '\0' ) {
88                 Entry *matched = NULL;
89
90                 /* get parent with reader lock */
91                 rc = dn2entry_r( be, ltid, pdn, &p, &matched );
92                 ch_free( pdn );
93
94                 switch( rc ) {
95                 case 0:
96                 case DB_NOTFOUND:
97                         break;
98                 case DB_LOCK_DEADLOCK:
99                 case DB_LOCK_NOTGRANTED:
100                         goto retry;
101                 default:
102                         rc = LDAP_OTHER;
103                         text = "internal error";
104                         goto return_results;
105                 }
106
107                 if ( p == NULL ) {
108                         char *matched_dn;
109                         struct berval **refs;
110
111                         if ( matched != NULL ) {
112                                 matched_dn = ch_strdup( matched->e_dn );
113                                 refs = is_entry_referral( matched )
114                                         ? get_entry_referrals( be, conn, op, matched )
115                                         : NULL;
116                                 bdb_entry_return( be, matched );
117
118                         } else {
119                                 matched_dn = NULL;
120                                 refs = default_referral;
121                         }
122
123                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n",
124                                 0, 0, 0 );
125
126                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
127                             matched_dn, NULL, refs, NULL );
128
129                         if( matched != NULL ) {
130                                 ber_bvecfree( refs );
131                                 ch_free( matched_dn );
132                         }
133
134                         goto done;
135                 }
136
137                 if ( ! access_allowed( be, conn, op, p,
138                         children, NULL, ACL_WRITE ) )
139                 {
140                         Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n",
141                                 0, 0, 0 );
142                         rc = LDAP_INSUFFICIENT_ACCESS;
143                         text = "no write access to parent", NULL, NULL;
144                         goto return_results;;
145                 }
146
147                 if ( is_entry_alias( p ) ) {
148                         /* parent is an alias, don't allow add */
149                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n",
150                                 0, 0, 0 );
151                         rc = LDAP_ALIAS_PROBLEM;
152                         text = "parent is an alias";
153                         goto return_results;;
154                 }
155
156                 if ( is_entry_referral( p ) ) {
157                         /* parent is a referral, don't allow add */
158                         char *matched_dn = ch_strdup( p->e_dn );
159                         struct berval **refs = is_entry_referral( p )
160                                 ? get_entry_referrals( be, conn, op, p )
161                                 : NULL;
162
163                         Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
164                                 0, 0, 0 );
165
166                         send_ldap_result( conn, op, rc = LDAP_REFERRAL,
167                             matched_dn, NULL, refs, NULL );
168
169                         ber_bvecfree( refs );
170                         free( matched_dn );
171                         goto done;
172                 }
173
174                 /* free parent and writer lock */
175                 bdb_entry_return( be, p );
176                 p = NULL;
177
178         } else {
179                 if( pdn != NULL ) {
180                         free(pdn);
181                 }
182
183                 /*
184                  * no parent!
185                  *      must be adding entry to at suffix
186                  *  or with parent ""
187                  */
188                 if ( !be_isroot( be, op->o_ndn )) {
189                         Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n",
190                                 pdn == NULL ? "suffix" : "entry at root",
191                                 0, 0 );
192                         rc = LDAP_INSUFFICIENT_ACCESS;
193                         goto return_results;
194                 }
195         }
196
197         /* dn2id index */
198         rc = bdb_dn2id_add( be, ltid, e->e_ndn, e->e_id );
199         if ( rc != 0 ) {
200                 Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
201                         db_strerror(rc), rc, 0 );
202
203                 switch( rc ) {
204                 case DB_LOCK_DEADLOCK:
205                 case DB_LOCK_NOTGRANTED:
206                         goto retry;
207                 case DB_KEYEXIST:
208                         rc = LDAP_ALREADY_EXISTS;
209                         break;
210                 default:
211                         rc = LDAP_OTHER;
212                 }
213                 goto return_results;
214         }
215
216         /* id2entry index */
217         rc = bdb_id2entry_add( be, ltid, e );
218         if ( rc != 0 ) {
219                 Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n",
220                         0, 0, 0 );
221                 switch( rc ) {
222                 case DB_LOCK_DEADLOCK:
223                 case DB_LOCK_NOTGRANTED:
224                         goto retry;
225                 default:
226                         rc = LDAP_OTHER;
227                 }
228                 text = "entry store failed";
229                 goto return_results;
230         }
231
232 #if 0
233         /* attribute indexes */
234         if ( index_entry_add( be, e, e->e_attrs ) != LDAP_SUCCESS ) {
235                 Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n",
236                         0, 0, 0 );
237                 switch( rc ) {
238                 case DB_LOCK_DEADLOCK:
239                 case DB_LOCK_NOTGRANTED:
240                         goto retry;
241                 default:
242                         rc = LDAP_OTHER;
243                 }
244                 text = "index generation failed";
245                 goto return_results;
246         }
247 #endif
248
249         rc = txn_commit( ltid, 0 );
250         ltid = NULL;
251         op->o_private = NULL;
252
253         if( rc == 0 ) {
254                 Debug( LDAP_DEBUG_TRACE,
255                         "bdb_add: txn_commit failed: %s (%d)\n",
256                         db_strerror(rc), rc, 0 );
257                 rc = LDAP_OTHER;
258                 text = "commit failed";
259         } else {
260                 Debug( LDAP_DEBUG_TRACE,
261                         "bdb_add: added id=%08x dn=\"%s\"\n",
262                         e->e_id, e->e_dn, 0 );
263                 rc = LDAP_SUCCESS;
264                 text = NULL;
265         }
266
267 return_results:
268         send_ldap_result( conn, op, rc,
269                 NULL, text, NULL, NULL );
270
271 done:
272         if (p != NULL) {
273                 /* free parent and writer lock */
274                 bdb_entry_return( be, p ); 
275         }
276
277         if( ltid != NULL ) {
278                 txn_abort( ltid );
279                 op->o_private = NULL;
280         }
281
282         return rc;
283 }