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