]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modify.c
Sync with HEAD
[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, 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         if ( !SLAP_SHADOW( op->o_bd ))
245                 slap_mods_opattrs( op, op->orm_modlist, 1 );
246
247         /* grab giant lock for writing */
248         ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
249
250         /* acquire and lock entry */
251         e = dn2entry_w( op->o_bd, &op->o_req_ndn, &matched );
252
253         /* FIXME: dn2entry() should return non-glue entry */
254         if (( e == NULL ) || ( !manageDSAit && e && is_entry_glue( e ))) {
255                 if ( matched != NULL ) {
256                         rs->sr_matched = ber_strdup_x( matched->e_dn, op->o_tmpmemctx );
257                         rs->sr_ref = is_entry_referral( matched )
258                                 ? get_entry_referrals( op, matched )
259                                 : NULL;
260                         cache_return_entry_r( &li->li_cache, matched );
261                 } else {
262                         rs->sr_ref = referral_rewrite( default_referral, NULL,
263                                                 &op->o_req_dn, LDAP_SCOPE_DEFAULT );
264                 }
265
266                 rs->sr_err = LDAP_REFERRAL;
267                 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
268                 goto return_results;
269         }
270
271         if ( !manageDSAit && is_entry_referral( e ) )
272         {
273                 /* parent is a referral, don't allow add */
274                 /* parent is an alias, don't allow add */
275                 rs->sr_ref = get_entry_referrals( op, e );
276
277                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
278                     0, 0 );
279
280                 rs->sr_err = LDAP_REFERRAL;
281                 rs->sr_matched = ber_strdup_x( e->e_name.bv_val, op->o_tmpmemctx );
282                 rs->sr_flags = REP_MATCHED_MUSTBEFREED | REP_REF_MUSTBEFREED;
283                 goto return_results;
284         }
285         
286         /* Modify the entry */
287         rs->sr_err = ldbm_modify_internal( op, op->oq_modify.rs_modlist, e,
288                 &rs->sr_text, textbuf, textlen );
289
290         /* change the entry itself */
291         if( rs->sr_err == LDAP_SUCCESS ) {
292                 if ( id2entry_add( op->o_bd, e ) != 0 ) {
293                         rs->sr_err = LDAP_OTHER;
294                         rs->sr_text = "id2entry failure";
295                 }
296         }
297
298 return_results:;
299         cache_return_entry_w( &li->li_cache, e );
300         ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
301
302         send_ldap_result( op, rs );
303         if ( !SLAP_SHADOW( op->o_bd ))
304                 slap_graduate_commit_csn( op );
305
306         rs->sr_text = NULL;
307         return rs->sr_err;
308 }