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