]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modify.c
Rework error handling. Add error descriptions.
[openldap] / servers / slapd / back-ldbm / modify.c
1 /* modify.c - ldbm backend modify routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 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
12 #include <ac/string.h>
13 #include <ac/socket.h>
14 #include <ac/time.h>
15
16 #include "slap.h"
17 #include "back-ldbm.h"
18 #include "proto-back-ldbm.h"
19
20 static int add_values LDAP_P(( Entry *e, Modification *mod, char *dn ));
21 static int delete_values LDAP_P(( Entry *e, Modification *mod, char *dn ));
22 static int replace_values LDAP_P(( Entry *e, Modification *mod, char *dn ));
23
24 /* We need this function because of LDAP modrdn. If we do not 
25  * add this there would be a bunch of code replication here 
26  * and there and of course the likelihood of bugs increases.
27  * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
28  */ 
29
30 int ldbm_modify_internal(
31     Backend     *be,
32     Connection  *conn,
33     Operation   *op,
34     char        *dn,
35     Modifications       *modlist,
36     Entry       *e 
37 )
38 {
39         int err;
40         Modification    *mod;
41         Modifications   *ml;
42         Attribute       *save_attrs;
43
44         if ( !acl_check_modlist( be, conn, op, e, modlist )) {
45                 return LDAP_INSUFFICIENT_ACCESS;
46         }
47
48         save_attrs = e->e_attrs;
49         e->e_attrs = attrs_dup( e->e_attrs );
50
51         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
52                 mod = &ml->sml_mod;
53
54 #ifdef SLAPD_SCHEMA_NOT_COMPAT
55                 switch ( mod->sm_op )
56 #else
57                 switch ( mod->mod_op )
58 #endif
59                 {
60                 case LDAP_MOD_ADD:
61                         err = add_values( e, mod, op->o_ndn );
62                         break;
63
64                 case LDAP_MOD_DELETE:
65                         err = delete_values( e, mod, op->o_ndn );
66                         break;
67
68                 case LDAP_MOD_REPLACE:
69                         err = replace_values( e, mod, op->o_ndn );
70                         break;
71
72                 case SLAP_MOD_SOFTADD:
73                         /* Avoid problems in index_add_mods()
74                          * We need to add index if necessary.
75                          */
76 #ifdef SLAPD_SCHEMA_NOT_COMPAT
77                         mod->sm_op = LDAP_MOD_ADD;
78 #else
79                         mod->mod_op = LDAP_MOD_ADD;
80 #endif
81                         err = add_values( e, mod, op->o_ndn );
82                         if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
83                                 err = LDAP_SUCCESS;
84 #ifdef SLAPD_SCHEMA_NOT_COMPAT
85                                 mod->sm_op = SLAP_MOD_SOFTADD;
86 #else
87                                 mod->mod_op = SLAP_MOD_SOFTADD;
88 #endif
89  
90                         }
91                         break;
92                 }
93
94                 if ( err != LDAP_SUCCESS ) {
95                         attrs_free( e->e_attrs );
96                         e->e_attrs = save_attrs;
97                         /* unlock entry, delete from cache */
98                         return err; 
99                 }
100         }
101
102         /* check for abandon */
103         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
104         if ( op->o_abandon ) {
105                 attrs_free( e->e_attrs );
106                 e->e_attrs = save_attrs;
107                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
108                 return SLAPD_ABANDON;
109         }
110         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
111
112         /* check that the entry still obeys the schema */
113         if ( schema_check_entry( e ) != 0 ) {
114                 attrs_free( e->e_attrs );
115                 e->e_attrs = save_attrs;
116                 Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
117                 return LDAP_OBJECT_CLASS_VIOLATION;
118         }
119
120         /* check for abandon */
121         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
122         if ( op->o_abandon ) {
123                 attrs_free( e->e_attrs );
124                 e->e_attrs = save_attrs;
125                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
126                 return SLAPD_ABANDON;
127         }
128         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
129
130         /* remove old indices */
131         if( save_attrs != NULL ) {
132                 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
133                         mod = &ml->sml_mod;
134 #ifdef SLAPD_SCHEMA_NOT_COMPAT
135                         if ( mod->sm_op == LDAP_MOD_REPLACE )
136 #else
137                         if ( mod->mod_op == LDAP_MOD_REPLACE )
138 #endif
139                         {
140 #ifdef SLAPD_SCHEMA_NOT_COMPAT
141                                 /* not yet implemented */
142 #else
143                                 /* Need to remove all values from indexes */
144                                 Attribute *a = attr_find( save_attrs, mod->mod_type );
145
146                                 if( a != NULL ) {
147                                         (void) index_change_values( be,
148                                                 mod->mod_type,
149                                                 a->a_vals,
150                                                 e->e_id,
151                                                 SLAP_INDEX_DELETE_OP);
152                                 }
153 #endif
154                         }
155                 }
156                 attrs_free( save_attrs );
157         }
158
159         /* modify indexes */
160         if ( index_add_mods( be, modlist, e->e_id ) != 0 ) {
161                 /* our indices are likely hosed */
162                 return LDAP_OTHER;
163         }
164
165         return LDAP_SUCCESS;
166 }
167
168
169 int
170 ldbm_back_modify(
171     Backend     *be,
172     Connection  *conn,
173     Operation   *op,
174     char        *dn,
175     char        *ndn,
176     Modifications       *modlist
177 )
178 {
179         int rc;
180         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
181         Entry           *matched;
182         Entry           *e;
183         int             manageDSAit = get_manageDSAit( op );
184
185         Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
186
187         /* acquire and lock entry */
188         if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
189                 char* matched_dn = NULL;
190                 struct berval **refs = NULL;
191
192                 if ( matched != NULL ) {
193                         matched_dn = ch_strdup( matched->e_dn );
194                         refs = is_entry_referral( matched )
195                                 ? get_entry_referrals( be, conn, op, matched )
196                                 : NULL;
197                         cache_return_entry_r( &li->li_cache, matched );
198                 } else {
199                         refs = default_referral;
200                 }
201
202                 send_ldap_result( conn, op, LDAP_REFERRAL,
203                         matched_dn, NULL, refs, NULL );
204
205                 if ( matched != NULL ) {
206                         ber_bvecfree( refs );
207                         free( matched_dn );
208                 }
209
210                 return( -1 );
211         }
212
213     if ( !manageDSAit && is_entry_referral( e ) ) {
214                 /* parent is a referral, don't allow add */
215                 /* parent is an alias, don't allow add */
216                 struct berval **refs = get_entry_referrals( be,
217                         conn, op, e );
218
219                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
220                     0, 0 );
221
222                 send_ldap_result( conn, op, LDAP_REFERRAL,
223                     e->e_dn, NULL, refs, NULL );
224
225                 ber_bvecfree( refs );
226
227                 goto error_return;
228         }
229         
230         /* Modify the entry */
231         rc = ldbm_modify_internal( be, conn, op, ndn, modlist, e );
232
233         if( rc != LDAP_SUCCESS ) {
234                 if( rc != SLAPD_ABANDON ) {
235                         send_ldap_result( conn, op, rc,
236                                 NULL, NULL, NULL, NULL );
237                 }
238
239                 goto error_return;
240         }
241
242         /* change the entry itself */
243         if ( id2entry_add( be, e ) != 0 ) {
244                 send_ldap_result( conn, op, LDAP_OTHER,
245                         NULL, NULL, NULL, NULL );
246                 goto error_return;
247         }
248
249         send_ldap_result( conn, op, LDAP_SUCCESS,
250                 NULL, NULL, NULL, NULL );
251
252         cache_return_entry_w( &li->li_cache, e );
253         return( 0 );
254
255 error_return:;
256         cache_return_entry_w( &li->li_cache, e );
257         return( -1 );
258 }
259
260 static int
261 add_values(
262     Entry       *e,
263     Modification        *mod,
264     char        *dn
265 )
266 {
267 #ifdef SLAPD_SCHEMA_NOT_COMPAT
268         /* not yet implemented */
269 #else
270         int             i;
271         Attribute       *a;
272
273         /* check if the values we're adding already exist */
274         if ( (a = attr_find( e->e_attrs, mod->mod_type )) != NULL ) {
275                 for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
276                         if ( value_find( a->a_vals, mod->mod_bvalues[i],
277                             a->a_syntax, 3 ) == 0 ) {
278                                 return( LDAP_TYPE_OR_VALUE_EXISTS );
279                         }
280                 }
281         }
282
283         /* no - add them */
284         if( attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 ) {
285                 return( LDAP_CONSTRAINT_VIOLATION );
286         }
287 #endif
288
289         return( LDAP_SUCCESS );
290 }
291
292 static int
293 delete_values(
294     Entry       *e,
295     Modification        *mod,
296     char        *dn
297 )
298 {
299 #ifdef SLAPD_SCHEMA_NOT_COMPAT
300         /* not yet implemented */
301 #else
302         int             i, j, k, found;
303         Attribute       *a;
304
305         /* delete the entire attribute */
306         if ( mod->mod_bvalues == NULL ) {
307                 Debug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
308                     mod->mod_type, 0, 0 );
309                 return( attr_delete( &e->e_attrs, mod->mod_type ) ?
310                     LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
311         }
312
313         /* delete specific values - find the attribute first */
314         if ( (a = attr_find( e->e_attrs, mod->mod_type )) == NULL ) {
315                 Debug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
316                     mod->mod_type, 0, 0 );
317                 return( LDAP_NO_SUCH_ATTRIBUTE );
318         }
319
320         /* find each value to delete */
321         for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
322                 found = 0;
323                 for ( j = 0; a->a_vals[j] != NULL; j++ ) {
324                         if ( value_cmp( mod->mod_bvalues[i], a->a_vals[j],
325                             a->a_syntax, 3 ) != 0 ) {
326                                 continue;
327                         }
328                         found = 1;
329
330                         /* found a matching value - delete it */
331                         ber_bvfree( a->a_vals[j] );
332                         for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
333                                 a->a_vals[k - 1] = a->a_vals[k];
334                         }
335                         a->a_vals[k - 1] = NULL;
336
337                         /* delete the entire attribute, if no values remain */
338                         if ( a->a_vals[0] == NULL) {
339                                 Debug( LDAP_DEBUG_ARGS,
340                                         "removing entire attribute %s\n",
341                                         mod->mod_type, 0, 0 );
342                                 if ( attr_delete( &e->e_attrs, mod->mod_type ) ) {
343                                         return LDAP_NO_SUCH_ATTRIBUTE;
344                                 }
345                         }
346
347                         break;
348                 }
349
350                 /* looked through them all w/o finding it */
351                 if ( ! found ) {
352                         Debug( LDAP_DEBUG_ARGS,
353                             "could not find value for attr %s\n",
354                             mod->mod_type, 0, 0 );
355                         return( LDAP_NO_SUCH_ATTRIBUTE );
356                 }
357         }
358 #endif
359
360         return( LDAP_SUCCESS );
361 }
362
363 static int
364 replace_values(
365     Entry       *e,
366     Modification        *mod,
367     char        *dn
368 )
369 {
370 #ifdef SLAPD_SCHEMA_NOT_COMPAT
371         /* not yet implemented */
372 #else
373         (void) attr_delete( &e->e_attrs, mod->mod_type );
374
375         if ( mod->mod_bvalues != NULL &&
376                 attr_merge( e, mod->mod_type, mod->mod_bvalues ) != 0 )
377         {
378                 return( LDAP_CONSTRAINT_VIOLATION );
379         }
380 #endif
381
382         return( LDAP_SUCCESS );
383 }