add.c 5.13 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
/* add.c - ldap ldbm back-end add routine */

3
4
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
#include <stdio.h>
6
7
8
9

#include <ac/socket.h>
#include <ac/string.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
10
11
#include "slap.h"
#include "back-ldbm.h"
12
#include "proto-back-ldbm.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
13
14
15
16
17
18
19
20
21
22

int
ldbm_back_add(
    Backend	*be,
    Connection	*conn,
    Operation	*op,
    Entry	*e
)
{
	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
23
	char		*dn = NULL, *pdn;
24
	Entry		*p = NULL;
25
26
	int			rootlock = 0;
	int			rc = -1; 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27

28
	dn = dn_normalize( ch_strdup( e->e_dn ) );
29
30
31

	Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", dn, 0, 0);

32
	/* nobody else can add until we lock our parent */
33
34
	pthread_mutex_lock(&li->li_add_mutex);

35
	if ( ( dn2id( be, dn ) ) != NOID ) {
36
		pthread_mutex_unlock(&li->li_add_mutex);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37
38
39
40
41
		entry_free( e );
		free( dn );
		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
		return( -1 );
	}
42

Kurt Zeilenga's avatar
Kurt Zeilenga committed
43
	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
44
45
		pthread_mutex_unlock(&li->li_add_mutex);

46
47
48
		Debug( LDAP_DEBUG_TRACE, "entry failed schema check\n",
			0, 0, 0 );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
		entry_free( e );
		free( dn );
		send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, "",
		    "" );
		return( -1 );
	}

	/*
	 * 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.
	 */

	if ( (pdn = dn_parent( be, dn )) != NULL ) {
63
		char *matched = NULL;
64

65
66
		/* get parent with writer lock */
		if ( (p = dn2entry_w( be, pdn, &matched )) == NULL ) {
67
			pthread_mutex_unlock(&li->li_add_mutex);
68
69
			Debug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0,
			    0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
70
71
			send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
			    matched, "" );
72

Kurt Zeilenga's avatar
Kurt Zeilenga committed
73
74
75
			if ( matched != NULL ) {
				free( matched );
			}
76

77
78
			entry_free( e );
			free( dn );
79
			free( pdn );
80
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
82
		}

83
84
85
86
87
88
89
90
91
		/* don't need the add lock anymore */
		pthread_mutex_unlock(&li->li_add_mutex);

		free(pdn);

		if ( matched != NULL ) {
			free( matched );
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
92
		if ( ! access_allowed( be, conn, op, p, "children", NULL,
93
94
		    op->o_dn, ACL_WRITE ) )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
95
96
97
98
			Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
			    0, 0 );
			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
			    "", "" );
99

100
101
102
			/* free parent and writer lock */
			cache_return_entry_w( &li->li_cache, p ); 

103
104
105
			entry_free( e );
			free( dn );
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
106
		}
107

Kurt Zeilenga's avatar
Kurt Zeilenga committed
108
	} else {
109
		/* no parent, must be adding entry to root */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
110
		if ( ! be_isroot( be, op->o_dn ) ) {
111
			pthread_mutex_unlock(&li->li_add_mutex);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
112
113
114
115
			Debug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0,
			    0, 0 );
			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
			    "", "" );
116

117
118
119
			entry_free( e );
			free( dn );
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
120
		}
121
122
123
124
125
126

		/*
		 * no parent, acquire the root write lock
		 * and release the add lock.
		 */
		pthread_mutex_lock(&li->li_root_mutex);
127
		rootlock = 1;
128
		pthread_mutex_unlock(&li->li_add_mutex);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
130
	}

131
132
133
134
135
136
137
138
	/*
	 * Try to add the entry to the cache, assign it a new dnid
	 * and mark it locked.  This should only fail if the entry
	 * already exists.
	 */

	e->e_id = next_id( be );
	if ( cache_add_entry_lock( &li->li_cache, e, ENTRY_STATE_CREATING ) != 0 ) {
139
140
141
		if( p != NULL) {
			/* free parent and writer lock */
			cache_return_entry_w( &li->li_cache, p ); 
142
143
		}
		if ( rootlock ) {
144
145
146
			/* release root lock */
			pthread_mutex_unlock(&li->li_root_mutex);
		}
147
148
149
150
151
152
153
154
155
156
157
158
159
160

		Debug( LDAP_DEBUG_ANY, "cache_add_entry_lock failed\n", 0, 0,
		    0 );
		next_id_return( be, e->e_id );
                
		/* XXX this should be ok, no other thread should have access
		 * because e hasn't been added to the cache yet
		 */
		entry_free( e );
		free( dn );
		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", "" );
		return( -1 );
	}

161
162
163
	/* acquire writer lock */
	entry_rdwr_lock(e, 1);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
164
165
166
167
168
169
170
	/*
	 * add it to the id2children index for the parent
	 */

	if ( id2children_add( be, p, e ) != 0 ) {
		Debug( LDAP_DEBUG_TRACE, "id2children_add failed\n", 0,
		    0, 0 );
171
172
173
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );

		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
174
175
176
177
178
179
180
181
182
183
184
185
	}

	/*
	 * Add the entry to the attribute indexes, then add it to
	 * the id2children index, dn2id index, and the id2entry index.
	 */

	/* attribute indexes */
	if ( index_add_entry( be, e ) != 0 ) {
		Debug( LDAP_DEBUG_TRACE, "index_add_entry failed\n", 0,
		    0, 0 );
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
186
187

		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
188
189
190
191
192
193
194
	}

	/* dn2id index */
	if ( dn2id_add( be, dn, e->e_id ) != 0 ) {
		Debug( LDAP_DEBUG_TRACE, "dn2id_add failed\n", 0,
		    0, 0 );
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
195
196

		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
197
198
199
200
201
202
203
204
	}

	/* id2entry index */
	if ( id2entry_add( be, e ) != 0 ) {
		Debug( LDAP_DEBUG_TRACE, "id2entry_add failed\n", 0,
		    0, 0 );
		(void) dn2id_delete( be, dn );
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
205
206

		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
207
208
209
	}

	send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
210
211
212
	rc = 0;

return_results:;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
213
214
	if ( dn != NULL )
		free( dn );
215

Kurt Zeilenga's avatar
Kurt Zeilenga committed
216
217
	cache_set_state( &li->li_cache, e, 0 );

218
	if (p != NULL) {
219
220
		/* free parent and writer lock */
		cache_return_entry_w( &li->li_cache, p ); 
221
	}
222

223
	if ( rootlock ) {
224
225
		/* release root lock */
		pthread_mutex_unlock(&li->li_root_mutex);
226
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
227

228
229
	/* free entry and writer lock */
	cache_return_entry_w( &li->li_cache, e ); 
230

231
	return( rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
232
}