]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/modify.c
Remove lint
[openldap] / servers / slapd / back-bdb / modify.c
1 /* modify.c - bdb backend modify routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11 #include <ac/string.h>
12 #include <ac/time.h>
13
14 #include "back-bdb.h"
15 #include "external.h"
16
17 static int add_values( Entry *e, Modification *mod, char *dn );
18 static int delete_values( Entry *e, Modification *mod, char *dn );
19 static int replace_values( Entry *e, Modification *mod, char *dn );
20
21 int bdb_modify_internal(
22         BackendDB *be,
23         Connection *conn,
24         Operation *op,
25         DB_TXN *tid,
26         Modifications *modlist,
27         Entry *e,
28         const char **text,
29         char *textbuf,
30         size_t textlen )
31 {
32         int rc, err;
33         Modification    *mod;
34         Modifications   *ml;
35         Attribute       *save_attrs;
36
37         Debug( LDAP_DEBUG_TRACE, "bdb_modify_internal: 0x%08lx: %s\n",
38                 e->e_id, e->e_dn, 0);
39
40         if ( !acl_check_modlist( be, conn, op, e, modlist )) {
41                 return LDAP_INSUFFICIENT_ACCESS;
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->sml_next ) {
48                 mod = &ml->sml_mod;
49
50                 switch ( mod->sm_op ) {
51                 case LDAP_MOD_ADD:
52                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: add\n", 0, 0, 0);
53                         err = add_values( e, mod, op->o_ndn );
54
55                         if( err != LDAP_SUCCESS ) {
56                                 *text = "modify: add values failed";
57                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
58                                         err, *text, 0);
59                         }
60                         break;
61
62                 case LDAP_MOD_DELETE:
63                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: delete\n", 0, 0, 0);
64                         err = delete_values( e, mod, op->o_ndn );
65                         assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
66                         if( err != LDAP_SUCCESS ) {
67                                 *text = "modify: delete values failed";
68                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
69                                         err, *text, 0);
70                         }
71                         break;
72
73                 case LDAP_MOD_REPLACE:
74                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: replace\n", 0, 0, 0);
75                         err = replace_values( e, mod, op->o_ndn );
76                         assert( err != LDAP_TYPE_OR_VALUE_EXISTS );
77                         if( err != LDAP_SUCCESS ) {
78                                 *text = "modify: replace values failed";
79                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
80                                         err, *text, 0);
81                         }
82                         break;
83
84                 case SLAP_MOD_SOFTADD:
85                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: softadd\n", 0, 0, 0);
86                         /* Avoid problems in index_add_mods()
87                          * We need to add index if necessary.
88                          */
89                         mod->sm_op = LDAP_MOD_ADD;
90                         err = add_values( e, mod, op->o_ndn );
91
92                         if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
93                                 err = LDAP_SUCCESS;
94                         }
95
96                         if( err != LDAP_SUCCESS ) {
97                                 *text = "modify: (soft)add values failed";
98                                 Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
99                                         err, *text, 0);
100                         }
101                         break;
102
103                 default:
104                         Debug(LDAP_DEBUG_ANY, "bdb_modify_internal: invalid op %d\n",
105                                 mod->sm_op, 0, 0);
106                         *text = "Invalid modify operation";
107                         err = LDAP_OTHER;
108                         Debug(LDAP_DEBUG_ARGS, "bdb_modify_internal: %d %s\n",
109                                 err, *text, 0);
110                 }
111
112                 if ( err != LDAP_SUCCESS ) {
113                         attrs_free( e->e_attrs );
114                         e->e_attrs = save_attrs;
115                         /* unlock entry, delete from cache */
116                         return err; 
117                 }
118         }
119
120         /* check that the entry still obeys the schema */
121         rc = entry_schema_check( e, save_attrs, text, textbuf, textlen );
122         if ( rc != LDAP_SUCCESS ) {
123                 attrs_free( e->e_attrs );
124                 e->e_attrs = save_attrs;
125                 Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n",
126                         *text, 0, 0 );
127                 return rc;
128         }
129
130 #if 0
131         /* delete indices for old attributes */
132         rc = index_entry_del( be, tid, e, save_attrs);
133
134         /* add indices for new attributes */
135         rc = index_entry_add( be, tid, e, e->e_attrs);
136 #endif
137
138         attrs_free( save_attrs );
139
140         return rc;
141 }
142
143
144 int
145 bdb_modify(
146         BackendDB       *be,
147         Connection      *conn,
148         Operation       *op,
149         const char      *dn,
150         const char      *ndn,
151         Modifications   *modlist )
152 {
153         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
154         int rc;
155         Entry           *matched;
156         Entry           *e;
157         int             manageDSAit = get_manageDSAit( op );
158         const char *text = NULL;
159         char textbuf[SLAP_TEXT_BUFLEN];
160         size_t textlen = sizeof textbuf;
161         DB_TXN  *ltid;
162         struct bdb_op_info opinfo;
163
164         Debug( LDAP_DEBUG_ARGS, "bdb_modify: %s\n", dn, 0, 0 );
165
166         if (0) {
167 retry:  /* transaction retry */
168                 Debug(LDAP_DEBUG_TRACE,
169                         "bdb_modify: retrying...\n", 0, 0, 0);
170                 rc = txn_abort( ltid );
171                 ltid = NULL;
172                 op->o_private = NULL;
173                 if( rc != 0 ) {
174                         rc = LDAP_OTHER;
175                         text = "internal error";
176                         goto return_results;
177                 }
178         }
179
180         /* begin transaction */
181         rc = txn_begin( bdb->bi_dbenv, NULL, &ltid, 0 );
182         text = NULL;
183         if( rc != 0 ) {
184                 Debug( LDAP_DEBUG_TRACE,
185                         "bdb_modify: txn_begin failed: %s (%d)\n",
186                         db_strerror(rc), rc, 0 );
187                 rc = LDAP_OTHER;
188                 text = "internal error";
189                 goto return_results;
190         }
191
192         opinfo.boi_bdb = be;
193         opinfo.boi_txn = ltid;
194         opinfo.boi_err = 0;
195         op->o_private = &opinfo;
196
197         /* get entry */
198         rc = bdb_dn2entry( be, ltid, ndn, &e, &matched, 0 );
199
200         if ( rc != 0 ) {
201                 Debug( LDAP_DEBUG_TRACE,
202                         "bdb_modify: dn2entry failed (%d)\n",
203                         rc, 0, 0 );
204                 switch( rc ) {
205                 case DB_LOCK_DEADLOCK:
206                 case DB_LOCK_NOTGRANTED:
207                         goto retry;
208                 case DB_NOTFOUND:
209                         break;
210                 default:
211                         rc = LDAP_OTHER;
212                 }
213                 text = "internal error";
214                 goto return_results;
215         }
216
217         /* acquire and lock entry */
218         if ( e == NULL ) {
219                 char* matched_dn = NULL;
220                 struct berval **refs = NULL;
221
222                 if ( matched != NULL ) {
223                         matched_dn = ch_strdup( matched->e_dn );
224                         refs = is_entry_referral( matched )
225                                 ? get_entry_referrals( be, conn, op, matched )
226                                 : NULL;
227                         bdb_entry_return( be, matched );
228                         matched = NULL;
229
230                 } else {
231                         refs = default_referral;
232                 }
233
234                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
235                         matched_dn, NULL, refs, NULL );
236
237                 if ( matched != NULL ) {
238                         ber_bvecfree( refs );
239                         free( matched_dn );
240                 }
241
242                 return rc;
243         }
244
245         if ( !manageDSAit && is_entry_referral( e ) ) {
246                 /* parent is a referral, don't allow add */
247                 /* parent is an alias, don't allow add */
248                 struct berval **refs = get_entry_referrals( be,
249                         conn, op, e );
250
251                 Debug( LDAP_DEBUG_TRACE,
252                         "bdb_modify: entry is referral\n",
253                         0, 0, 0 );
254
255                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
256                         e->e_dn, NULL, refs, NULL );
257
258                 ber_bvecfree( refs );
259                 goto done;
260         }
261         
262         /* Modify the entry */
263         rc = bdb_modify_internal( be, conn, op, ltid, modlist, e,
264                 &text, textbuf, textlen );
265
266         if( rc != LDAP_SUCCESS ) {
267                 Debug( LDAP_DEBUG_TRACE,
268                         "bdb_modify: modify failed (%d)\n",
269                         rc, 0, 0 );
270                 switch( rc ) {
271                 case DB_LOCK_DEADLOCK:
272                 case DB_LOCK_NOTGRANTED:
273                         goto retry;
274                 }
275                 goto return_results;
276         }
277
278         /* change the entry itself */
279         rc = bdb_id2entry_update( be, ltid, e );
280         if ( rc != 0 ) {
281                 Debug( LDAP_DEBUG_TRACE,
282                         "bdb_modify: id2entry update failed (%d)\n",
283                         rc, 0, 0 );
284                 switch( rc ) {
285                 case DB_LOCK_DEADLOCK:
286                 case DB_LOCK_NOTGRANTED:
287                         goto retry;
288                 }
289                 text = "entry update failed";
290                 goto return_results;
291         }
292
293         rc = txn_commit( ltid, 0 );
294         ltid = NULL;
295         op->o_private = NULL;
296
297         if( rc != 0 ) {
298                 Debug( LDAP_DEBUG_TRACE,
299                         "bdb_modify: txn_commit failed: %s (%d)\n",
300                         db_strerror(rc), rc, 0 );
301                 rc = LDAP_OTHER;
302                 text = "commit failed";
303         } else {
304                 Debug( LDAP_DEBUG_TRACE,
305                         "bdb_modify: updated id=%08x dn=\"%s\"\n",
306                         e->e_id, e->e_dn, 0 );
307                 rc = LDAP_SUCCESS;
308                 text = NULL;
309         }
310
311 return_results:
312         send_ldap_result( conn, op, rc,
313                 NULL, text, NULL, NULL );
314
315         if(rc == LDAP_SUCCESS && bdb->bi_txn_cp ) {
316                 ldap_pvt_thread_yield();
317                 txn_checkpoint( bdb->bi_dbenv,
318                         bdb->bi_txn_cp_kbyte, bdb->bi_txn_cp_min, 0 );
319         }
320
321 done:
322         if( ltid != NULL ) {
323                 txn_abort( ltid );
324                 op->o_private = NULL;
325         }
326
327         if( e != NULL ) {
328                 bdb_entry_return( be, e );
329         }
330         return rc;
331 }
332
333 static int
334 add_values(
335         Entry   *e,
336         Modification    *mod,
337         char    *dn
338 )
339 {
340         int             i;
341         Attribute       *a;
342
343         /* char *desc = mod->sm_desc->ad_cname->bv_val; */
344         MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
345
346         a = attr_find( e->e_attrs, mod->sm_desc );
347
348         /* check if the values we're adding already exist */
349         if ( a != NULL ) {
350                 if( mr == NULL || !mr->smr_match ) {
351                         /* do not allow add of additional attribute
352                                 if no equality rule exists */
353                         return LDAP_INAPPROPRIATE_MATCHING;
354                 }
355
356                 for ( i = 0; mod->sm_bvalues[i] != NULL; i++ ) {
357                         int rc;
358                         int j;
359                         const char *text = NULL;
360                         struct berval *asserted;
361
362                         rc = value_normalize( mod->sm_desc,
363                                 SLAP_MR_EQUALITY,
364                                 mod->sm_bvalues[i],
365                                 &asserted,
366                                 &text );
367
368                         if( rc != LDAP_SUCCESS ) return rc;
369
370                         for ( j = 0; a->a_vals[j] != NULL; j++ ) {
371                                 int match;
372                                 int rc = value_match( &match, mod->sm_desc, mr,
373                                         SLAP_MR_MODIFY_MATCHING,
374                                         a->a_vals[j], asserted, &text );
375
376                                 if( rc == LDAP_SUCCESS && match == 0 ) {
377                                         ber_bvfree( asserted );
378                                         return LDAP_TYPE_OR_VALUE_EXISTS;
379                                 }
380                         }
381
382                         ber_bvfree( asserted );
383                 }
384         }
385
386         /* no - add them */
387         if( attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 ) {
388                 /* this should return result return of attr_merge */
389                 return LDAP_OTHER;
390         }
391
392         return LDAP_SUCCESS;
393 }
394
395 static int
396 delete_values(
397         Entry   *e,
398         Modification    *mod,
399         char    *dn
400 )
401 {
402         int             i, j, k, found;
403         Attribute       *a;
404         char *desc = mod->sm_desc->ad_cname->bv_val;
405         MatchingRule *mr = mod->sm_desc->ad_type->sat_equality;
406
407         /* delete the entire attribute */
408         if ( mod->sm_bvalues == NULL ) {
409                 Debug( LDAP_DEBUG_TRACE,
410                         "bdb_modify_delete: removing entire attribute %s\n",
411                         desc, 0, 0 );
412                 return attr_delete( &e->e_attrs, mod->sm_desc )
413                         ? LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS;
414         }
415
416         if( mr == NULL || !mr->smr_match ) {
417                 /* disallow specific attributes from being deleted if
418                         no equality rule */
419                 return LDAP_INAPPROPRIATE_MATCHING;
420         }
421
422         /* delete specific values - find the attribute first */
423         if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
424                 Debug( LDAP_DEBUG_TRACE,
425                         "bdb_modify_delete: could not find attribute %s\n",
426                         desc, 0, 0 );
427                 return LDAP_NO_SUCH_ATTRIBUTE;
428         }
429
430         /* find each value to delete */
431         for ( i = 0; mod->sm_bvalues[i] != NULL; i++ ) {
432                 int rc;
433                 const char *text = NULL;
434
435                 struct berval *asserted;
436
437                 rc = value_normalize( mod->sm_desc,
438                         SLAP_MR_EQUALITY,
439                         mod->sm_bvalues[i],
440                         &asserted,
441                         &text );
442
443                 if( rc != LDAP_SUCCESS ) return rc;
444
445                 found = 0;
446                 for ( j = 0; a->a_vals[j] != NULL; j++ ) {
447                         int match;
448                         int rc = value_match( &match, mod->sm_desc, mr,
449                                 SLAP_MR_MODIFY_MATCHING,
450                                 a->a_vals[j], asserted, &text );
451
452                         if( rc == LDAP_SUCCESS && match != 0 ) {
453                                 continue;
454                         }
455
456                         /* found a matching value */
457                         found = 1;
458
459                         /* delete it */
460                         ber_bvfree( a->a_vals[j] );
461                         for ( k = j + 1; a->a_vals[k] != NULL; k++ ) {
462                                 a->a_vals[k - 1] = a->a_vals[k];
463                         }
464                         a->a_vals[k - 1] = NULL;
465
466                         break;
467                 }
468
469                 ber_bvfree( asserted );
470
471                 /* looked through them all w/o finding it */
472                 if ( ! found ) {
473                         Debug( LDAP_DEBUG_TRACE,
474                                 "bdb_modify_delete: could not find value for attr %s\n",
475                                 desc, 0, 0 );
476                         return LDAP_NO_SUCH_ATTRIBUTE;
477                 }
478         }
479
480         /* if no values remain, delete the entire attribute */
481         if ( a->a_vals[0] == NULL ) {
482                 Debug( LDAP_DEBUG_TRACE,
483                         "bdb_modify_delete: removing entire attribute %s\n",
484                         desc, 0, 0 );
485                 if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
486                         return LDAP_NO_SUCH_ATTRIBUTE;
487                 }
488         }
489
490         return LDAP_SUCCESS;
491 }
492
493 static int
494 replace_values(
495         Entry   *e,
496         Modification    *mod,
497         char    *dn
498 )
499 {
500         int rc = attr_delete( &e->e_attrs, mod->sm_desc );
501
502         if( rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE ) {
503                 return rc;
504         }
505
506         if ( mod->sm_bvalues != NULL &&
507                 attr_merge( e, mod->sm_desc, mod->sm_bvalues ) != 0 )
508         {
509                 return LDAP_OTHER;
510         }
511
512         return LDAP_SUCCESS;
513 }