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