Newer
Older
/* add.c - ldap BerkeleyDB back-end add routine */
/* $OpenLDAP$ */
/*
* Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-bdb.h"
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
int
bdb_add(
Backend *be,
Connection *conn,
Operation *op,
Entry *e )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
char *pdn = NULL;
Entry *p = NULL;
int rc;
const char *text = NULL;
AttributeDescription *children = slap_schema.si_ad_children;
DB_TXN *ltid = NULL;
Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
/* check entry's schema */
rc = entry_schema_check( e, NULL, &text );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE,
"bdb_add: entry failed schema check: %s (%d)\n",
text, rc, 0 );
goto return_results;
}
/*
* acquire an ID outside of the operation transaction
* to avoid serializing adds.
*/
rc = bdb_next_id( be, NULL, &e->e_id );
if( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE,
"bdb_add: next_id failed (%d)\n",
rc, 0, 0 );
rc = LDAP_OTHER;
text = "internal error";
goto return_results;
}
retry: rc = txn_abort( ltid );
ltid = NULL;
op->o_private = NULL;
if( rc != 0 ) {
rc = LDAP_OTHER;
text = "internal error";
goto return_results;
}
}
/* begin transaction */
rc = txn_begin( bdb->bi_dbenv, NULL, <id, 0 );
if( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE,
"bdb_add: txn_begin failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
rc = LDAP_OTHER;
text = "internal error";
goto return_results;
}
/*
* Get the parent dn and see if the corresponding entry exists.
* If the parent does not exist, only allow the "root" user to
* add the entry.
*/
pdn = dn_parent( be, e->e_ndn );
if( pdn != NULL && *pdn != '\0' ) {
Entry *matched = NULL;
/* get parent with reader lock */
rc = dn2entry_r( be, ltid, pdn, &p, &matched );
ch_free( pdn );
switch( rc ) {
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
default:
rc = LDAP_OTHER;
text = "internal error";
goto return_results;
}
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
if ( p == NULL ) {
char *matched_dn;
struct berval **refs;
if ( matched != NULL ) {
matched_dn = ch_strdup( matched->e_dn );
refs = is_entry_referral( matched )
? get_entry_referrals( be, conn, op, matched )
: NULL;
bdb_entry_return( be, matched );
} else {
matched_dn = NULL;
refs = default_referral;
}
Debug( LDAP_DEBUG_TRACE, "bdb_add: parent does not exist\n",
0, 0, 0 );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
matched_dn, NULL, refs, NULL );
if( matched != NULL ) {
ber_bvecfree( refs );
ch_free( matched_dn );
}
goto done;
}
if ( ! access_allowed( be, conn, op, p,
children, NULL, ACL_WRITE ) )
{
Debug( LDAP_DEBUG_TRACE, "bdb_add: no write access to parent\n",
0, 0, 0 );
rc = LDAP_INSUFFICIENT_ACCESS;
text = "no write access to parent", NULL, NULL;
goto return_results;;
}
if ( is_entry_alias( p ) ) {
/* parent is an alias, don't allow add */
Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is alias\n",
0, 0, 0 );
rc = LDAP_ALIAS_PROBLEM;
text = "parent is an alias";
goto return_results;;
}
if ( is_entry_referral( p ) ) {
/* parent is a referral, don't allow add */
char *matched_dn = ch_strdup( p->e_dn );
struct berval **refs = is_entry_referral( p )
? get_entry_referrals( be, conn, op, p )
: NULL;
Debug( LDAP_DEBUG_TRACE, "bdb_add: parent is referral\n",
0, 0, 0 );
send_ldap_result( conn, op, rc = LDAP_REFERRAL,
matched_dn, NULL, refs, NULL );
ber_bvecfree( refs );
free( matched_dn );
goto done;
}
/* free parent and writer lock */
bdb_entry_return( be, p );
p = NULL;
} else {
if( pdn != NULL ) {
free(pdn);
}
/*
* no parent!
* must be adding entry to at suffix
* or with parent ""
*/
if ( !be_isroot( be, op->o_ndn )) {
Debug( LDAP_DEBUG_TRACE, "bdb_add: %s denied\n",
pdn == NULL ? "suffix" : "entry at root",
0, 0 );
rc = LDAP_INSUFFICIENT_ACCESS;
goto return_results;
}
}
/* dn2id index */
rc = bdb_dn2id_add( be, ltid, e->e_ndn, e->e_id );
if ( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
switch( rc ) {
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
case DB_KEYEXIST:
rc = LDAP_OTHER;
}
goto return_results;
}
/* id2entry index */
rc = bdb_id2entry_add( be, ltid, e );
if ( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE, "bdb_add: id2entry_add failed\n",
0, 0, 0 );
switch( rc ) {
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
default:
rc = LDAP_OTHER;
}
text = "entry store failed";
goto return_results;
}
#if 0
/* attribute indexes */
if ( index_entry_add( be, e, e->e_attrs ) != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE, "bdb_add: index_entry_add failed\n",
0, 0, 0 );
switch( rc ) {
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto retry;
default:
rc = LDAP_OTHER;
}
text = "index generation failed";
goto return_results;
}
#endif
rc = txn_commit( ltid, 0 );
ltid = NULL;
if( rc == 0 ) {
Debug( LDAP_DEBUG_TRACE,
"bdb_add: txn_commit failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
rc = LDAP_OTHER;
text = "commit failed";
} else {
Debug( LDAP_DEBUG_TRACE,
"bdb_add: added id=%08x dn=\"%s\"\n",
e->e_id, e->e_dn, 0 );
rc = LDAP_SUCCESS;
text = NULL;
}
return_results:
send_ldap_result( conn, op, rc,
done:
if (p != NULL) {
/* free parent and writer lock */
bdb_entry_return( be, p );
}
if( ltid != NULL ) {
txn_abort( ltid );