]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modify.c
Cleanup result handling
[openldap] / servers / slapd / back-ldbm / modify.c
1 /* modify.c - ldbm backend modify routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20
21 #include <ac/string.h>
22 #include <ac/socket.h>
23 #include <ac/time.h>
24
25 #include "slap.h"
26 #include "back-ldbm.h"
27 #include "proto-back-ldbm.h"
28
29 /* We need this function because of LDAP modrdn. If we do not 
30  * add this there would be a bunch of code replication here 
31  * and there and of course the likelihood of bugs increases.
32  * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
33  */ 
34 int ldbm_modify_internal(
35     Operation   *op,
36     Modifications       *modlist,
37     Entry       *e,
38         const char **text,
39         char *textbuf,
40         size_t textlen
41 )
42 {
43         int rc = LDAP_SUCCESS;
44         Modification    *mod;
45         Modifications   *ml;
46         Attribute       *save_attrs;
47         Attribute       *ap;
48
49 #ifdef NEW_LOGGING
50         LDAP_LOG( BACK_LDBM, ENTRY,  "ldbm_modify_internal: %s\n", e->e_name.bv_val, 0, 0 );
51 #else
52         Debug(LDAP_DEBUG_TRACE, "ldbm_modify_internal: %s\n", e->e_name.bv_val, 0, 0);
53 #endif
54
55
56         if ( !acl_check_modlist( op, e, modlist )) {
57                 return LDAP_INSUFFICIENT_ACCESS;
58         }
59
60         save_attrs = e->e_attrs;
61         e->e_attrs = attrs_dup( e->e_attrs );
62
63         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
64                 mod = &ml->sml_mod;
65
66                 switch ( mod->sm_op ) {
67                 case LDAP_MOD_ADD:
68 #ifdef NEW_LOGGING
69                         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_modify_internal: add\n", 0, 0, 0);
70 #else
71                         Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: add\n", 0, 0, 0);
72 #endif
73
74                         rc = modify_add_values( e, mod, get_permissiveModify( op ),
75                                                 text, textbuf, textlen );
76                         if( rc != LDAP_SUCCESS ) {
77 #ifdef NEW_LOGGING
78                                 LDAP_LOG( BACK_LDBM, INFO, 
79                                         "ldbm_modify_internal: failed %d (%s)\n", rc, *text, 0 );
80 #else
81                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
82                                         rc, *text, 0);
83 #endif
84                         }
85                         break;
86
87                 case LDAP_MOD_DELETE:
88 #ifdef NEW_LOGGING
89                         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_modify_internal: delete\n", 0,0,0);
90 #else
91                         Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: delete\n", 0, 0, 0);
92 #endif
93
94                         rc = modify_delete_values( e, mod, get_permissiveModify( op ),
95                                                         text, textbuf, textlen );
96                         assert( rc != LDAP_TYPE_OR_VALUE_EXISTS );
97                         if( rc != LDAP_SUCCESS ) {
98 #ifdef NEW_LOGGING
99                                 LDAP_LOG( BACK_LDBM, INFO, 
100                                         "ldbm_modify_internal: failed %d (%s)\n", rc, *text, 0 );
101 #else
102                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
103                                         rc, *text, 0);
104 #endif
105                         }
106                         break;
107
108                 case LDAP_MOD_REPLACE:
109 #ifdef NEW_LOGGING
110                         LDAP_LOG( BACK_LDBM, DETAIL1, "ldbm_modify_internal:  replace\n",0,0,0);
111 #else
112                         Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: replace\n", 0, 0, 0);
113 #endif
114
115                         rc = modify_replace_values( e, mod, get_permissiveModify( op ),
116                                                         text, textbuf, textlen );
117                         if( rc != LDAP_SUCCESS ) {
118 #ifdef NEW_LOGGING
119                                 LDAP_LOG( BACK_LDBM, INFO, 
120                                         "ldbm_modify_internal: failed %d (%s)\n", rc, *text, 0 );
121 #else
122                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
123                                         rc, *text, 0);
124 #endif
125                         }
126                         break;
127
128                 case LDAP_MOD_INCREMENT:
129 #ifdef NEW_LOGGING
130                         LDAP_LOG( BACK_LDBM, DETAIL1,
131                                 "ldbm_modify_internal:  increment\n",0,0,0);
132 #else
133                         Debug(LDAP_DEBUG_ARGS,
134                                 "ldbm_modify_internal:  increment\n",0,0,0);
135 #endif
136
137                         rc = modify_increment_values( e, mod, get_permissiveModify( op ),
138                                 text, textbuf, textlen );
139                         if( rc != LDAP_SUCCESS ) {
140 #ifdef NEW_LOGGING
141                                 LDAP_LOG( BACK_LDBM, INFO, 
142                                         "ldbm_modify_internal: failed %d (%s)\n", rc, *text, 0 );
143 #else
144                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
145                                         rc, *text, 0);
146 #endif
147                         }
148                         break;
149
150                 case SLAP_MOD_SOFTADD:
151 #ifdef NEW_LOGGING
152                         LDAP_LOG( BACK_LDBM, DETAIL1, 
153                                 "ldbm_modify_internal: softadd\n", 0, 0, 0 );
154 #else
155                         Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: softadd\n", 0, 0, 0);
156 #endif
157
158                         /* Avoid problems in index_add_mods()
159                          * We need to add index if necessary.
160                          */
161                         mod->sm_op = LDAP_MOD_ADD;
162
163                         rc = modify_add_values( e, mod, get_permissiveModify( op ),
164                                                 text, textbuf, textlen );
165                         mod->sm_op = SLAP_MOD_SOFTADD;
166                         if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
167                                 rc = LDAP_SUCCESS;
168                         }
169
170                         if( rc != LDAP_SUCCESS ) {
171 #ifdef NEW_LOGGING
172                                 LDAP_LOG( BACK_LDBM, INFO, 
173                                            "ldbm_modify_internal: failed %d (%s)\n", rc, *text, 0 );
174 #else
175                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
176                                         rc, *text, 0);
177 #endif
178                         }
179                         break;
180
181                 default:
182 #ifdef NEW_LOGGING
183                         LDAP_LOG( BACK_LDBM, ERR, 
184                                 "ldbm_modify_internal: invalid op %d\n", mod->sm_op, 0, 0 );
185 #else
186                         Debug(LDAP_DEBUG_ANY, "ldbm_modify_internal: invalid op %d\n",
187                                 mod->sm_op, 0, 0);
188 #endif
189
190                         rc = LDAP_OTHER;
191                         *text = "Invalid modify operation";
192 #ifdef NEW_LOGGING
193                         LDAP_LOG( BACK_LDBM, INFO, 
194                                 "ldbm_modify_internal: %d (%s)\n", rc, *text, 0 );
195 #else
196                         Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
197                                 rc, *text, 0);
198 #endif
199                 }
200
201                 if ( rc != LDAP_SUCCESS ) {
202                         goto exit;
203                 }
204
205                 /* If objectClass was modified, reset the flags */
206                 if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
207                         e->e_ocflags = 0;
208                 }
209
210                 /* check if modified attribute was indexed */
211                 rc = index_is_indexed( op->o_bd, mod->sm_desc );
212                 if ( rc == LDAP_SUCCESS ) {
213                         ap = attr_find( save_attrs, mod->sm_desc );
214                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
215
216                         ap = attr_find( e->e_attrs, mod->sm_desc );
217                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
218                 }
219         }
220
221         /* check that the entry still obeys the schema */
222         rc = entry_schema_check( op->o_bd, e, save_attrs, text, textbuf, textlen );
223
224         if ( rc != LDAP_SUCCESS ) {
225 #ifdef NEW_LOGGING
226                 LDAP_LOG( BACK_LDBM, ERR, 
227                         "ldbm_modify_internal: entry failed schema check: %s\n", 
228                         *text, 0, 0 );
229 #else
230                 Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n",
231                         *text, 0, 0 );
232 #endif
233
234                 goto exit;
235         }
236
237         /* check for abandon */
238         if ( op->o_abandon ) {
239                 rc = SLAPD_ABANDON;
240                 goto exit;
241         }
242
243         /* update the indices of the modified attributes */
244
245         /* start with deleting the old index entries */
246         for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
247                 if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
248                         rc = index_values( op, ap->a_desc,
249                                 ap->a_nvals,
250                                 e->e_id, SLAP_INDEX_DELETE_OP );
251                         if ( rc != LDAP_SUCCESS ) {
252 #ifdef NEW_LOGGING
253                                 LDAP_LOG( BACK_LDBM, ERR,
254                                         "ldbm_modify_internal: Attribute index delete failure\n",
255                                         0, 0, 0 );
256 #else
257                                 Debug( LDAP_DEBUG_ANY,
258                                        "Attribute index delete failure",
259                                        0, 0, 0 );
260 #endif
261                                 goto exit;
262                         }
263                         ap->a_flags &= ~SLAP_ATTR_IXDEL;
264                 }
265         }
266
267         /* add the new index entries */
268         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
269                 if ( ap->a_flags & SLAP_ATTR_IXADD ) {
270                         rc = index_values( op, ap->a_desc,
271                                 ap->a_nvals,
272                                 e->e_id, SLAP_INDEX_ADD_OP );
273                         if ( rc != LDAP_SUCCESS ) {
274 #ifdef NEW_LOGGING
275                                 LDAP_LOG( BACK_LDBM, ERR,
276                                         "ldbm_modify_internal: Attribute index add failure\n",
277                                         0, 0, 0 );
278 #else
279                                 Debug( LDAP_DEBUG_ANY,
280                                        "Attribute index add failure",
281                                        0, 0, 0 );
282 #endif
283                                 goto exit;
284                         }
285                         ap->a_flags &= ~SLAP_ATTR_IXADD;
286                 }
287         }
288
289 exit:
290         if ( rc == LDAP_SUCCESS ) {
291                 attrs_free( save_attrs );
292         } else {
293                 for ( ap = save_attrs; ap; ap = ap->a_next ) {
294                         ap->a_flags = 0;
295                 }
296                 attrs_free( e->e_attrs );
297                 e->e_attrs = save_attrs;
298         }
299
300         return rc;
301 }
302
303 int
304 ldbm_back_modify(
305     Operation   *op,
306     SlapReply   *rs )
307 {
308         struct ldbminfo *li = (struct ldbminfo *) op->o_bd->be_private;
309         Entry           *matched;
310         Entry           *e;
311         int             manageDSAit = get_manageDSAit( op );
312         char textbuf[SLAP_TEXT_BUFLEN];
313         size_t textlen = sizeof textbuf;
314
315 #ifdef NEW_LOGGING
316         LDAP_LOG( BACK_LDBM, ENTRY, "ldbm_back_modify: enter\n", 0, 0, 0);
317 #else
318         Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
319 #endif
320
321         /* grab giant lock for writing */
322         ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
323
324         /* acquire and lock entry */
325         e = dn2entry_w( op->o_bd, &op->o_req_ndn, &matched );
326
327         /* FIXME: dn2entry() should return non-glue entry */
328         if (( e == NULL ) || ( !manageDSAit && e && is_entry_glue( e ))) {
329                 if ( matched != NULL ) {
330                         rs->sr_matched = ch_strdup( matched->e_dn );
331                         rs->sr_ref = is_entry_referral( matched )
332                                 ? get_entry_referrals( op, matched )
333                                 : NULL;
334                         cache_return_entry_r( &li->li_cache, matched );
335                 } else {
336                         BerVarray deref = NULL;
337                         if ( !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) {
338                                 syncinfo_t *si;
339                                 LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) {
340                                         struct berval tmpbv;
341                                         ber_dupbv( &tmpbv, &si->si_provideruri_bv[0] );
342                                         ber_bvarray_add( &deref, &tmpbv );
343                                 }
344                         } else {
345                                 deref = default_referral;
346                         }
347                         rs->sr_ref = referral_rewrite( deref, NULL, &op->o_req_dn,
348                                                         LDAP_SCOPE_DEFAULT );
349                 }
350
351                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
352                 rs->sr_err = LDAP_REFERRAL;
353                 send_ldap_result( op, rs );
354
355                 if ( rs->sr_ref ) ber_bvarray_free( rs->sr_ref );
356                 free( (char *)rs->sr_matched );
357
358                 rs->sr_ref = NULL;
359                 rs->sr_matched = NULL;
360                 return rs->sr_err;
361         }
362
363         if ( !manageDSAit && is_entry_referral( e ) )
364         {
365                 /* parent is a referral, don't allow add */
366                 /* parent is an alias, don't allow add */
367                 rs->sr_ref = get_entry_referrals( op, e );
368
369 #ifdef NEW_LOGGING
370                 LDAP_LOG( BACK_LDBM, INFO, 
371                            "ldbm_back_modify: entry (%s) is referral\n", op->o_req_ndn.bv_val, 0, 0 );
372 #else
373                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
374                     0, 0 );
375 #endif
376
377                 rs->sr_err = LDAP_REFERRAL;
378                 rs->sr_matched = e->e_name.bv_val;
379                 send_ldap_result( op, rs );
380
381                 if ( rs->sr_ref ) ber_bvarray_free( rs->sr_ref );
382                 rs->sr_ref = NULL;
383                 rs->sr_matched = NULL;
384                 goto error_return;
385         }
386         
387         /* Modify the entry */
388         rs->sr_err = ldbm_modify_internal( op, op->oq_modify.rs_modlist, e,
389                 &rs->sr_text, textbuf, textlen );
390
391         if( rs->sr_err != LDAP_SUCCESS ) {
392                 if( rs->sr_err != SLAPD_ABANDON ) {
393                         send_ldap_result( op, rs );
394                 }
395
396                 goto error_return;
397         }
398
399         /* change the entry itself */
400         if ( id2entry_add( op->o_bd, e ) != 0 ) {
401                 send_ldap_error( op, rs, LDAP_OTHER,
402                         "id2entry failure" );
403                 rs->sr_err = LDAP_OTHER;
404                 goto error_return;
405         }
406
407         rs->sr_text = NULL;
408         send_ldap_error( op, rs, LDAP_SUCCESS,
409                 NULL );
410
411         cache_return_entry_w( &li->li_cache, e );
412         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
413
414         return LDAP_SUCCESS;
415
416 error_return:;
417         cache_return_entry_w( &li->li_cache, e );
418         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
419         rs->sr_text = NULL;
420         return rs->sr_err;
421 }