]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modify.c
ITS:3749: Extend manageDIT support to LDBM.
[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-2005 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         int rc = LDAP_SUCCESS;
43         Modification    *mod;
44         Modifications   *ml;
45         Attribute       *save_attrs;
46         Attribute       *ap;
47
48         Debug(LDAP_DEBUG_TRACE,
49                 "ldbm_modify_internal: %s\n",
50                 e->e_name.bv_val,
51                 get_permissiveModify(op) ? " (permissive)" : "",
52                 0 );
53
54         if ( !acl_check_modlist( op, e, modlist )) {
55                 return LDAP_INSUFFICIENT_ACCESS;
56         }
57
58         save_attrs = e->e_attrs;
59         e->e_attrs = attrs_dup( e->e_attrs );
60
61         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
62                 mod = &ml->sml_mod;
63
64                 switch ( mod->sm_op ) {
65                 case LDAP_MOD_ADD:
66                         Debug(LDAP_DEBUG_ARGS,
67                                 "ldbm_modify_internal: add\n", 0, 0, 0);
68
69                         rc = modify_add_values( e, mod, get_permissiveModify( op ),
70                                 text, textbuf, textlen );
71                         if( rc != LDAP_SUCCESS ) {
72                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
73                                         rc, *text, 0);
74                         }
75                         break;
76
77                 case LDAP_MOD_DELETE:
78                         Debug(LDAP_DEBUG_ARGS,
79                                 "ldbm_modify_internal: delete\n", 0, 0, 0);
80
81                         rc = modify_delete_values( e, mod, get_permissiveModify( op ),
82                                 text, textbuf, textlen );
83                         assert( rc != LDAP_TYPE_OR_VALUE_EXISTS );
84                         if( rc != LDAP_SUCCESS ) {
85                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
86                                         rc, *text, 0);
87                         }
88                         break;
89
90                 case LDAP_MOD_REPLACE:
91                         Debug(LDAP_DEBUG_ARGS,
92                                 "ldbm_modify_internal: replace\n", 0, 0, 0);
93
94                         rc = modify_replace_values( e, mod, get_permissiveModify( op ),
95                                 text, textbuf, textlen );
96                         if( rc != LDAP_SUCCESS ) {
97                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
98                                         rc, *text, 0);
99                         }
100                         break;
101
102                 case LDAP_MOD_INCREMENT:
103                         Debug(LDAP_DEBUG_ARGS,
104                                 "ldbm_modify_internal:  increment\n",0,0,0);
105
106                         rc = modify_increment_values( e, mod, get_permissiveModify( op ),
107                                 text, textbuf, textlen );
108                         if( rc != LDAP_SUCCESS ) {
109                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
110                                         rc, *text, 0);
111                         }
112                         break;
113
114                 case SLAP_MOD_SOFTADD:
115                         Debug(LDAP_DEBUG_ARGS,
116                                 "ldbm_modify_internal: softadd\n", 0, 0, 0);
117
118                         /* Avoid problems in index_add_mods()
119                          * We need to add index if necessary.
120                          */
121                         mod->sm_op = LDAP_MOD_ADD;
122
123                         rc = modify_add_values( e, mod, get_permissiveModify( op ),
124                                 text, textbuf, textlen );
125                         mod->sm_op = SLAP_MOD_SOFTADD;
126                         if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
127                                 rc = LDAP_SUCCESS;
128                         }
129
130                         if( rc != LDAP_SUCCESS ) {
131                                 Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
132                                         rc, *text, 0);
133                         }
134                         break;
135
136                 default:
137                         Debug(LDAP_DEBUG_ANY, "ldbm_modify_internal: invalid op %d\n",
138                                 mod->sm_op, 0, 0);
139
140                         rc = LDAP_OTHER;
141                         *text = "Invalid modify operation";
142                         Debug(LDAP_DEBUG_ARGS, "ldbm_modify_internal: %d %s\n",
143                                 rc, *text, 0);
144                 }
145
146                 if ( rc != LDAP_SUCCESS ) {
147                         goto exit;
148                 }
149
150                 /* If objectClass was modified, reset the flags */
151                 if ( mod->sm_desc == slap_schema.si_ad_objectClass ) {
152                         e->e_ocflags = 0;
153                 }
154
155                 /* check if modified attribute was indexed */
156                 rc = index_is_indexed( op->o_bd, mod->sm_desc );
157                 if ( rc == LDAP_SUCCESS ) {
158                         ap = attr_find( save_attrs, mod->sm_desc );
159                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXDEL;
160
161                         ap = attr_find( e->e_attrs, mod->sm_desc );
162                         if ( ap ) ap->a_flags |= SLAP_ATTR_IXADD;
163                 }
164         }
165
166         /* check that the entry still obeys the schema */
167         rc = entry_schema_check( op->o_bd, e, save_attrs, get_manageDIT(op),
168                 text, textbuf, textlen );
169         if ( rc != LDAP_SUCCESS ) {
170                 Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n",
171                         *text, 0, 0 );
172
173                 goto exit;
174         }
175
176         /* check for abandon */
177         if ( op->o_abandon ) {
178                 rc = SLAPD_ABANDON;
179                 goto exit;
180         }
181
182         /* update the indices of the modified attributes */
183
184         /* start with deleting the old index entries */
185         for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) {
186                 if ( ap->a_flags & SLAP_ATTR_IXDEL ) {
187                         rc = index_values( op, ap->a_desc,
188                                 ap->a_nvals,
189                                 e->e_id, SLAP_INDEX_DELETE_OP );
190                         if ( rc != LDAP_SUCCESS ) {
191                                 Debug( LDAP_DEBUG_ANY,
192                                         "ldbm_modify_internal: Attribute index delete failure\n",
193                                         0, 0, 0 );
194                                 goto exit;
195                         }
196                         ap->a_flags &= ~SLAP_ATTR_IXDEL;
197                 }
198         }
199
200         /* add the new index entries */
201         for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
202                 if ( ap->a_flags & SLAP_ATTR_IXADD ) {
203                         rc = index_values( op, ap->a_desc,
204                                 ap->a_nvals,
205                                 e->e_id, SLAP_INDEX_ADD_OP );
206                         if ( rc != LDAP_SUCCESS ) {
207                                 Debug( LDAP_DEBUG_ANY,
208                                         "ldbm_modify_internal: Attribute index add failure\n",
209                                         0, 0, 0 );
210                                 goto exit;
211                         }
212                         ap->a_flags &= ~SLAP_ATTR_IXADD;
213                 }
214         }
215
216 exit:
217         if ( rc == LDAP_SUCCESS ) {
218                 attrs_free( save_attrs );
219         } else {
220                 for ( ap = save_attrs; ap; ap = ap->a_next ) {
221                         ap->a_flags = 0;
222                 }
223                 attrs_free( e->e_attrs );
224                 e->e_attrs = save_attrs;
225         }
226
227         return rc;
228 }
229
230 int
231 ldbm_back_modify(
232     Operation   *op,
233     SlapReply   *rs )
234 {
235         struct ldbminfo *li = (struct ldbminfo *) op->o_bd->be_private;
236         Entry           *matched;
237         Entry           *e;
238         int             manageDSAit = get_manageDSAit( op );
239         char textbuf[SLAP_TEXT_BUFLEN];
240         size_t textlen = sizeof textbuf;
241
242         Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
243
244         /* grab giant lock for writing */
245         ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
246
247         /* acquire and lock entry */
248         e = dn2entry_w( op->o_bd, &op->o_req_ndn, &matched );
249
250         /* FIXME: dn2entry() should return non-glue entry */
251         if (( e == NULL ) || ( !manageDSAit && e && is_entry_glue( e ))) {
252                 if ( matched != NULL ) {
253                         rs->sr_matched = ch_strdup( matched->e_dn );
254                         rs->sr_ref = is_entry_referral( matched )
255                                 ? get_entry_referrals( op, matched )
256                                 : NULL;
257                         cache_return_entry_r( &li->li_cache, matched );
258                 } else {
259                         rs->sr_ref = referral_rewrite( default_referral, NULL,
260                                                 &op->o_req_dn, LDAP_SCOPE_DEFAULT );
261                 }
262
263                 ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
264                 rs->sr_err = LDAP_REFERRAL;
265                 send_ldap_result( op, rs );
266
267                 if ( rs->sr_ref ) ber_bvarray_free( rs->sr_ref );
268                 free( (char *)rs->sr_matched );
269
270                 rs->sr_ref = NULL;
271                 rs->sr_matched = NULL;
272                 return rs->sr_err;
273         }
274
275         if ( !manageDSAit && is_entry_referral( e ) )
276         {
277                 /* parent is a referral, don't allow add */
278                 /* parent is an alias, don't allow add */
279                 rs->sr_ref = get_entry_referrals( op, e );
280
281                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
282                     0, 0 );
283
284                 rs->sr_err = LDAP_REFERRAL;
285                 rs->sr_matched = e->e_name.bv_val;
286                 send_ldap_result( op, rs );
287
288                 if ( rs->sr_ref ) ber_bvarray_free( rs->sr_ref );
289                 rs->sr_ref = NULL;
290                 rs->sr_matched = NULL;
291                 goto error_return;
292         }
293         
294         /* Modify the entry */
295         rs->sr_err = ldbm_modify_internal( op, op->oq_modify.rs_modlist, e,
296                 &rs->sr_text, textbuf, textlen );
297
298         if( rs->sr_err != LDAP_SUCCESS ) {
299                 if( rs->sr_err != SLAPD_ABANDON ) {
300                         send_ldap_result( op, rs );
301                 }
302
303                 goto error_return;
304         }
305
306         /* change the entry itself */
307         if ( id2entry_add( op->o_bd, e ) != 0 ) {
308                 send_ldap_error( op, rs, LDAP_OTHER,
309                         "id2entry failure" );
310                 rs->sr_err = LDAP_OTHER;
311                 goto error_return;
312         }
313
314         rs->sr_text = NULL;
315         send_ldap_error( op, rs, LDAP_SUCCESS,
316                 NULL );
317
318         cache_return_entry_w( &li->li_cache, e );
319         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
320
321         return LDAP_SUCCESS;
322
323 error_return:;
324         cache_return_entry_w( &li->li_cache, e );
325         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
326         rs->sr_text = NULL;
327         return rs->sr_err;
328 }