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