1 /* id2entry.c - routines to deal with the id2entry database */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2000-2021 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 #include <ac/string.h>
21 #include <ac/errno.h>
22
23 #include "back-mdb.h"
24
25 typedef struct Ecount {
26 ber_len_t len; /* total entry size */
27 ber_len_t dlen; /* contiguous data size */
28 int nattrs;
29 int nvals;
30 int offset;
31 Attribute *multi;
32 } Ecount;
33
34 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
35 Ecount *eh);
36 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data,
37 Ecount *ec);
38 static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals );
39
40 #define ID2VKSZ (sizeof(ID)+2)
41
42 int
mdb_id2v_compare(const MDB_val * usrkey,const MDB_val * curkey)43 mdb_id2v_compare(
44 const MDB_val *usrkey,
45 const MDB_val *curkey
46 )
47 {
48 unsigned short *uv, *cv;
49 ID ui, ci;
50 int rc;
51
52 memcpy(&ui, usrkey->mv_data, sizeof(ID));
53 memcpy(&ci, curkey->mv_data, sizeof(ID));
54 if (ui < ci)
55 return -1;
56 if (ui > ci)
57 return 1;
58 uv = usrkey->mv_data;
59 cv = curkey->mv_data;
60 return uv[sizeof(ID)/2] - cv[sizeof(ID)/2];
61 }
62
63 /* usrkey[0] is the key in DB format, as described at mdb_mval_put.
64 * usrkey[1] is the value we'll actually match against.
65 * usrkey[2] is the attributeDescription for this value.
66 */
67 int
mdb_id2v_dupsort(const MDB_val * usrkey,const MDB_val * curkey)68 mdb_id2v_dupsort(
69 const MDB_val *usrkey,
70 const MDB_val *curkey
71 )
72 {
73 AttributeDescription *ad = usrkey[2].mv_data;
74 struct berval bv1, bv2;
75 int rc, match, olen;
76 unsigned short s;
77 char *ptr;
78
79 ptr = curkey->mv_data + curkey->mv_size - 2;
80 memcpy(&s, ptr, 2);
81 bv2.bv_val = curkey->mv_data;
82 bv2.bv_len = curkey->mv_size - 3;
83 if (s)
84 bv2.bv_len -= (s+1);
85
86 bv1.bv_val = usrkey[1].mv_data;
87 bv1.bv_len = usrkey[1].mv_size;
88
89 if (ad && ad->ad_type->sat_equality) {
90 MatchingRule *mr = ad->ad_type->sat_equality;
91 rc = mr->smr_match(&match, SLAP_MR_EQUALITY
92 | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
93 | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
94 | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
95 ad->ad_type->sat_syntax, mr, &bv1, &bv2);
96 } else {
97 match = ber_bvcmp(&bv1, &bv2);
98 }
99
100 return match;
101 }
102
103 /* Values are stored as
104 * [normalized-value NUL ] original-value NUL 2-byte-len
105 * The trailing 2-byte-len is zero if there is no normalized value.
106 * Otherwise, it is the length of the original-value.
107 */
mdb_mval_put(Operation * op,MDB_cursor * mc,ID id,Attribute * a)108 int mdb_mval_put(Operation *op, MDB_cursor *mc, ID id, Attribute *a)
109 {
110 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
111 MDB_val key, data[3];
112 char *buf;
113 char ivk[ID2VKSZ];
114 unsigned i;
115 unsigned short s;
116 int rc, len;
117
118 memcpy(ivk, &id, sizeof(id));
119 s = mdb->mi_adxs[a->a_desc->ad_index];
120 memcpy(ivk+sizeof(ID), &s, 2);
121 key.mv_data = &ivk;
122 key.mv_size = sizeof(ivk);
123 if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass)
124 data[2].mv_data = NULL;
125 else
126 data[2].mv_data = a->a_desc;
127
128 for (i=0; i<a->a_numvals; i++) {
129 len = a->a_nvals[i].bv_len + 1 + 2;
130 if (a->a_nvals != a->a_vals) {
131 len += a->a_vals[i].bv_len + 1;
132 data[1].mv_data = a->a_nvals[i].bv_val;
133 data[1].mv_size = a->a_nvals[i].bv_len;
134 } else {
135 data[1].mv_data = a->a_vals[i].bv_val;
136 data[1].mv_size = a->a_vals[i].bv_len;
137 }
138 data[0].mv_size = len;
139 buf = op->o_tmpalloc( len, op->o_tmpmemctx );
140 data[0].mv_data = buf;
141 memcpy(buf, a->a_nvals[i].bv_val, a->a_nvals[i].bv_len);
142 buf += a->a_nvals[i].bv_len;
143 *buf++ = 0;
144 if (a->a_nvals != a->a_vals) {
145 s = a->a_vals[i].bv_len;
146 memcpy(buf, a->a_vals[i].bv_val, a->a_vals[i].bv_len);
147 buf += a->a_vals[i].bv_len;
148 *buf++ = 0;
149 memcpy(buf, &s, 2);
150 } else {
151 *buf++ = 0;
152 *buf++ = 0;
153 }
154 rc = mdb_cursor_put(mc, &key, data, 0);
155 op->o_tmpfree( data[0].mv_data, op->o_tmpmemctx );
156 if (rc)
157 return rc;
158 }
159 return 0;
160 }
161
mdb_mval_del(Operation * op,MDB_cursor * mc,ID id,Attribute * a)162 int mdb_mval_del(Operation *op, MDB_cursor *mc, ID id, Attribute *a)
163 {
164 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
165 MDB_val key, data[3];
166 char *ptr;
167 char ivk[ID2VKSZ];
168 unsigned i;
169 int rc;
170 unsigned short s;
171
172 memcpy(ivk, &id, sizeof(id));
173 s = mdb->mi_adxs[a->a_desc->ad_index];
174 memcpy(ivk+sizeof(ID), &s, 2);
175 key.mv_data = &ivk;
176 key.mv_size = sizeof(ivk);
177 if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass)
178 data[2].mv_data = NULL;
179 else
180 data[2].mv_data = a->a_desc;
181
182 if (a->a_numvals) {
183 for (i=0; i<a->a_numvals; i++) {
184 data[0].mv_data = a->a_nvals[i].bv_val;
185 data[0].mv_size = a->a_nvals[i].bv_len+1;
186 if (a->a_nvals != a->a_vals) {
187 data[1].mv_data = a->a_nvals[i].bv_val;
188 data[1].mv_size = a->a_nvals[i].bv_len;
189 } else {
190 data[1].mv_data = a->a_vals[i].bv_val;
191 data[1].mv_size = a->a_vals[i].bv_len;
192 }
193 rc = mdb_cursor_get(mc, &key, data, MDB_GET_BOTH_RANGE);
194 if (rc)
195 return rc;
196 rc = mdb_cursor_del(mc, 0);
197 if (rc)
198 return rc;
199 }
200 } else {
201 rc = mdb_cursor_get(mc, &key, data, MDB_SET);
202 if (rc)
203 return rc;
204 rc = mdb_cursor_del(mc, MDB_NODUPDATA);
205 }
206 return rc;
207 }
208
mdb_mval_get(Operation * op,MDB_cursor * mc,ID id,Attribute * a,int have_nvals)209 static int mdb_mval_get(Operation *op, MDB_cursor *mc, ID id, Attribute *a, int have_nvals)
210 {
211 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
212 MDB_val key, data[3];
213 char *ptr;
214 char ivk[ID2VKSZ];
215 unsigned i;
216 int rc = 0;
217 unsigned short s;
218
219 memcpy(ivk, &id, sizeof(id));
220 s = mdb->mi_adxs[a->a_desc->ad_index];
221 memcpy(ivk+sizeof(ID), &s, 2);
222 key.mv_data = &ivk;
223 key.mv_size = sizeof(ivk);
224
225 /* not needed */
226 if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass)
227 data[2].mv_data = NULL;
228 else
229 data[2].mv_data = a->a_desc;
230
231 if (have_nvals)
232 a->a_nvals = a->a_vals + a->a_numvals + 1;
233 else
234 a->a_nvals = a->a_vals;
235 for (i=0; i<a->a_numvals; i++) {
236 if (!i)
237 rc = mdb_cursor_get(mc, &key, data, MDB_SET);
238 else
239 rc = mdb_cursor_get(mc, &key, data, MDB_NEXT_DUP);
240 if (rc)
241 break;
242 ptr = (char*)data[0].mv_data + data[0].mv_size - 2;
243 memcpy(&s, ptr, 2);
244 if (have_nvals) {
245 a->a_nvals[i].bv_val = data[0].mv_data;
246 a->a_vals[i].bv_len = s;
247 a->a_vals[i].bv_val = ptr - a->a_vals[i].bv_len - 1;
248 a->a_nvals[i].bv_len = a->a_vals[i].bv_val - a->a_nvals[i].bv_val - 1;
249 } else {
250 assert(!s);
251 a->a_vals[i].bv_val = data[0].mv_data;
252 a->a_vals[i].bv_len = data[0].mv_size - 3;
253 }
254 }
255 a->a_numvals = i;
256 BER_BVZERO(&a->a_vals[i]);
257 if (have_nvals) {
258 BER_BVZERO(&a->a_nvals[i]);
259 }
260 return rc;
261 }
262
263 #define ADD_FLAGS (MDB_NOOVERWRITE|MDB_APPEND)
264
mdb_id2entry_put(Operation * op,MDB_txn * txn,MDB_cursor * mc,Entry * e,int flag)265 static int mdb_id2entry_put(
266 Operation *op,
267 MDB_txn *txn,
268 MDB_cursor *mc,
269 Entry *e,
270 int flag )
271 {
272 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
273 Ecount ec;
274 MDB_val key, data;
275 int rc, adding = flag, prev_ads = mdb->mi_numads;
276
277 /* We only store rdns, and they go in the dn2id database. */
278
279 key.mv_data = &e->e_id;
280 key.mv_size = sizeof(ID);
281
282 rc = mdb_entry_partsize( mdb, txn, e, &ec );
283 if (rc) {
284 rc = LDAP_OTHER;
285 goto fail;
286 }
287
288 flag |= MDB_RESERVE;
289
290 if (e->e_id < mdb->mi_nextid)
291 flag &= ~MDB_APPEND;
292
293 if (mdb->mi_maxentrysize && ec.len > mdb->mi_maxentrysize) {
294 rc = LDAP_ADMINLIMIT_EXCEEDED;
295 goto fail;
296 }
297
298 again:
299 data.mv_size = ec.dlen;
300 if ( mc )
301 rc = mdb_cursor_put( mc, &key, &data, flag );
302 else
303 rc = mdb_put( txn, mdb->mi_id2entry, &key, &data, flag );
304 if (rc == MDB_SUCCESS) {
305 rc = mdb_entry_encode( op, e, &data, &ec );
306 if( rc != LDAP_SUCCESS )
307 goto fail;
308 /* Handle adds of large multi-valued attrs here.
309 * Modifies handle them directly.
310 */
311 if (adding && ec.multi) {
312 MDB_cursor *mvc;
313 Attribute *a;
314 rc = mdb_cursor_open( txn, mdb->mi_dbis[MDB_ID2VAL], &mvc );
315 if( !rc ) {
316 for ( a = ec.multi; a; a=a->a_next ) {
317 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI))
318 continue;
319 rc = mdb_mval_put( op, mvc, e->e_id, a );
320 if( rc )
321 break;
322 }
323 mdb_cursor_close( mvc );
324 }
325 if ( rc ) {
326 Debug( LDAP_DEBUG_ANY,
327 "mdb_id2entry_put: mdb_mval_put failed: %s(%d) \"%s\"\n",
328 mdb_strerror(rc), rc,
329 e->e_nname.bv_val );
330 rc = LDAP_OTHER;
331 goto fail;
332 }
333 }
334 }
335 if (rc) {
336 /* Was there a hole from slapadd? */
337 if ( (flag & MDB_NOOVERWRITE) && data.mv_size == 0 ) {
338 flag &= ~ADD_FLAGS;
339 goto again;
340 }
341 Debug( LDAP_DEBUG_ANY,
342 "mdb_id2entry_put: mdb_put failed: %s(%d) \"%s\"\n",
343 mdb_strerror(rc), rc,
344 e->e_nname.bv_val );
345 if ( rc != MDB_KEYEXIST )
346 rc = LDAP_OTHER;
347 }
348 fail:
349 if (rc) {
350 mdb_ad_unwind( mdb, prev_ads );
351 }
352 return rc;
353 }
354
355 /*
356 * This routine adds (or updates) an entry on disk.
357 */
mdb_id2entry_add(Operation * op,MDB_txn * txn,MDB_cursor * mc,Entry * e)358 int mdb_id2entry_add(
359 Operation *op,
360 MDB_txn *txn,
361 MDB_cursor *mc,
362 Entry *e )
363 {
364 return mdb_id2entry_put(op, txn, mc, e, ADD_FLAGS);
365 }
366
mdb_id2entry_update(Operation * op,MDB_txn * txn,MDB_cursor * mc,Entry * e)367 int mdb_id2entry_update(
368 Operation *op,
369 MDB_txn *txn,
370 MDB_cursor *mc,
371 Entry *e )
372 {
373 return mdb_id2entry_put(op, txn, mc, e, 0);
374 }
375
mdb_id2edata(Operation * op,MDB_cursor * mc,ID id,MDB_val * data)376 int mdb_id2edata(
377 Operation *op,
378 MDB_cursor *mc,
379 ID id,
380 MDB_val *data )
381 {
382 MDB_val key;
383 int rc;
384
385 key.mv_data = &id;
386 key.mv_size = sizeof(ID);
387
388 /* fetch it */
389 rc = mdb_cursor_get( mc, &key, data, MDB_SET );
390 /* stubs from missing parents - DB is actually invalid */
391 if ( rc == MDB_SUCCESS && !data->mv_size )
392 rc = MDB_NOTFOUND;
393 return rc;
394 }
395
mdb_id2entry(Operation * op,MDB_cursor * mc,ID id,Entry ** e)396 int mdb_id2entry(
397 Operation *op,
398 MDB_cursor *mc,
399 ID id,
400 Entry **e )
401 {
402 MDB_val key, data;
403 int rc = 0;
404
405 *e = NULL;
406
407 key.mv_data = &id;
408 key.mv_size = sizeof(ID);
409
410 /* fetch it */
411 rc = mdb_cursor_get( mc, &key, &data, MDB_SET );
412 if ( rc == MDB_NOTFOUND ) {
413 /* Looking for root entry on an empty-dn suffix? */
414 if ( !id && BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] )) {
415 struct berval gluebv = BER_BVC("glue");
416 Entry *r = mdb_entry_alloc(op, 2, 4);
417 Attribute *a = r->e_attrs;
418 struct berval *bptr;
419
420 r->e_id = 0;
421 r->e_ocflags = SLAP_OC_GLUE|SLAP_OC__END;
422 bptr = a->a_vals;
423 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
424 a->a_desc = slap_schema.si_ad_objectClass;
425 a->a_nvals = a->a_vals;
426 a->a_numvals = 1;
427 *bptr++ = gluebv;
428 BER_BVZERO(bptr);
429 bptr++;
430 a->a_next = a+1;
431 a = a->a_next;
432 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
433 a->a_desc = slap_schema.si_ad_structuralObjectClass;
434 a->a_vals = bptr;
435 a->a_nvals = a->a_vals;
436 a->a_numvals = 1;
437 *bptr++ = gluebv;
438 BER_BVZERO(bptr);
439 a->a_next = NULL;
440 *e = r;
441 return MDB_SUCCESS;
442 }
443 }
444 /* stubs from missing parents - DB is actually invalid */
445 if ( rc == MDB_SUCCESS && !data.mv_size )
446 rc = MDB_NOTFOUND;
447 if ( rc ) return rc;
448
449 rc = mdb_entry_decode( op, mdb_cursor_txn( mc ), &data, id, e );
450 if ( rc ) return rc;
451
452 (*e)->e_id = id;
453 (*e)->e_name.bv_val = NULL;
454 (*e)->e_nname.bv_val = NULL;
455
456 return rc;
457 }
458
mdb_id2entry_delete(BackendDB * be,MDB_txn * tid,Entry * e)459 int mdb_id2entry_delete(
460 BackendDB *be,
461 MDB_txn *tid,
462 Entry *e )
463 {
464 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
465 MDB_dbi dbi = mdb->mi_id2entry;
466 MDB_val key;
467 MDB_cursor *mvc;
468 char kbuf[sizeof(ID) + sizeof(unsigned short)];
469 int rc;
470
471 memcpy( kbuf, &e->e_id, sizeof(ID) );
472 memset( kbuf+sizeof(ID), 0, sizeof(unsigned short) );
473 key.mv_data = kbuf;
474 key.mv_size = sizeof(kbuf);
475
476 /* delete from database */
477 rc = mdb_del( tid, dbi, &key, NULL );
478 if (rc)
479 return rc;
480 rc = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc );
481 if (rc)
482 return rc;
483
484 rc = mdb_cursor_get( mvc, &key, NULL, MDB_SET_RANGE );
485 if (rc) {
486 if (rc == MDB_NOTFOUND)
487 rc = MDB_SUCCESS;
488 return rc;
489 }
490 while (*(ID *)key.mv_data == e->e_id ) {
491 rc = mdb_cursor_del( mvc, MDB_NODUPDATA );
492 if (rc)
493 return rc;
494 rc = mdb_cursor_get( mvc, &key, NULL, MDB_GET_CURRENT );
495 if (rc) {
496 /* no record or DB is empty */
497 if (rc == MDB_NOTFOUND || rc == EINVAL)
498 rc = MDB_SUCCESS;
499 break;
500 }
501 }
502 return rc;
503 }
504
mdb_entry_alloc(Operation * op,int nattrs,int nvals)505 static Entry * mdb_entry_alloc(
506 Operation *op,
507 int nattrs,
508 int nvals )
509 {
510 Entry *e = op->o_tmpalloc( sizeof(Entry) +
511 nattrs * sizeof(Attribute) +
512 nvals * sizeof(struct berval), op->o_tmpmemctx );
513 BER_BVZERO(&e->e_bv);
514 e->e_private = e;
515 if (nattrs) {
516 e->e_attrs = (Attribute *)(e+1);
517 e->e_attrs->a_vals = (struct berval *)(e->e_attrs+nattrs);
518 } else {
519 e->e_attrs = NULL;
520 }
521
522 return e;
523 }
524
mdb_entry_return(Operation * op,Entry * e)525 int mdb_entry_return(
526 Operation *op,
527 Entry *e
528 )
529 {
530 if ( !e )
531 return 0;
532 if ( e->e_private ) {
533 if ( op->o_hdr && op->o_tmpmfuncs ) {
534 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
535 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
536 op->o_tmpfree( e, op->o_tmpmemctx );
537 } else {
538 ch_free( e->e_nname.bv_val );
539 ch_free( e->e_name.bv_val );
540 ch_free( e );
541 }
542 } else {
543 entry_free( e );
544 }
545 return 0;
546 }
547
mdb_entry_release(Operation * op,Entry * e,int rw)548 int mdb_entry_release(
549 Operation *op,
550 Entry *e,
551 int rw )
552 {
553 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
554 struct mdb_op_info *moi = NULL;
555
556 /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
557 SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
558
559 int release = 1;
560 if ( slapMode & SLAP_SERVER_MODE ) {
561 OpExtra *oex;
562 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
563 release = 0;
564 if ( oex->oe_key == mdb ) {
565 mdb_entry_return( op, e );
566 moi = (mdb_op_info *)oex;
567 /* If it was setup by entry_get we should probably free it */
568 if (( moi->moi_flag & (MOI_FREEIT|MOI_KEEPER)) == MOI_FREEIT ) {
569 moi->moi_ref--;
570 if ( moi->moi_ref < 1 ) {
571 mdb_txn_reset( moi->moi_txn );
572 moi->moi_ref = 0;
573 LDAP_SLIST_REMOVE( &op->o_extra, &moi->moi_oe, OpExtra, oe_next );
574 op->o_tmpfree( moi, op->o_tmpmemctx );
575 }
576 }
577 break;
578 }
579 }
580 }
581
582 if (release)
583 mdb_entry_return( op, e );
584
585 return 0;
586 }
587
588 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
589 */
mdb_entry_get(Operation * op,struct berval * ndn,ObjectClass * oc,AttributeDescription * at,int rw,Entry ** ent)590 int mdb_entry_get(
591 Operation *op,
592 struct berval *ndn,
593 ObjectClass *oc,
594 AttributeDescription *at,
595 int rw,
596 Entry **ent )
597 {
598 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
599 struct mdb_op_info *moi = NULL;
600 MDB_txn *txn = NULL;
601 Entry *e = NULL;
602 int rc;
603 const char *at_name = at ? at->ad_cname.bv_val : "(null)";
604
605 Debug( LDAP_DEBUG_ARGS,
606 "=> mdb_entry_get: ndn: \"%s\"\n", ndn->bv_val );
607 Debug( LDAP_DEBUG_ARGS,
608 "=> mdb_entry_get: oc: \"%s\", at: \"%s\"\n",
609 oc ? oc->soc_cname.bv_val : "(null)", at_name );
610
611 rc = mdb_opinfo_get( op, mdb, rw == 0, &moi );
612 if ( rc )
613 return LDAP_OTHER;
614 txn = moi->moi_txn;
615
616 /* can we find entry */
617 rc = mdb_dn2entry( op, txn, NULL, ndn, &e, NULL, 0 );
618 switch( rc ) {
619 case MDB_NOTFOUND:
620 case 0:
621 break;
622 default:
623 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
624 }
625 if (e == NULL) {
626 Debug( LDAP_DEBUG_ACL,
627 "=> mdb_entry_get: cannot find entry: \"%s\"\n",
628 ndn->bv_val );
629 rc = LDAP_NO_SUCH_OBJECT;
630 goto return_results;
631 }
632
633 Debug( LDAP_DEBUG_ACL,
634 "=> mdb_entry_get: found entry: \"%s\"\n",
635 ndn->bv_val );
636
637 if ( oc && !is_entry_objectclass( e, oc, 0 )) {
638 Debug( LDAP_DEBUG_ACL,
639 "<= mdb_entry_get: failed to find objectClass %s\n",
640 oc->soc_cname.bv_val );
641 rc = LDAP_NO_SUCH_ATTRIBUTE;
642 goto return_results;
643 }
644
645 /* NOTE: attr_find() or attrs_find()? */
646 if ( at && attr_find( e->e_attrs, at ) == NULL ) {
647 Debug( LDAP_DEBUG_ACL,
648 "<= mdb_entry_get: failed to find attribute %s\n",
649 at->ad_cname.bv_val );
650 rc = LDAP_NO_SUCH_ATTRIBUTE;
651 goto return_results;
652 }
653
654 return_results:
655 if( rc != LDAP_SUCCESS ) {
656 /* free entry */
657 mdb_entry_release( op, e, rw );
658 } else {
659 *ent = e;
660 }
661
662 Debug( LDAP_DEBUG_TRACE,
663 "mdb_entry_get: rc=%d\n",
664 rc );
665 return(rc);
666 }
667
668 static void
mdb_reader_free(void * key,void * data)669 mdb_reader_free( void *key, void *data )
670 {
671 MDB_txn *txn = data;
672
673 if ( txn ) mdb_txn_abort( txn );
674 }
675
676 /* free up any keys used by the main thread */
677 void
mdb_reader_flush(MDB_env * env)678 mdb_reader_flush( MDB_env *env )
679 {
680 void *data;
681 void *ctx = ldap_pvt_thread_pool_context();
682
683 if ( !ldap_pvt_thread_pool_getkey( ctx, env, &data, NULL ) ) {
684 ldap_pvt_thread_pool_setkey( ctx, env, NULL, 0, NULL, NULL );
685 mdb_reader_free( env, data );
686 }
687 }
688
689 extern MDB_txn *mdb_tool_txn;
690
691 int
mdb_opinfo_get(Operation * op,struct mdb_info * mdb,int rdonly,mdb_op_info ** moip)692 mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **moip )
693 {
694 int rc, renew = 0;
695 void *data;
696 void *ctx;
697 mdb_op_info *moi = NULL;
698 OpExtra *oex;
699
700 assert( op != NULL );
701
702 if ( !mdb || !moip ) return -1;
703
704 /* If no op was provided, try to find the ctx anyway... */
705 if ( op ) {
706 ctx = op->o_threadctx;
707 } else {
708 ctx = ldap_pvt_thread_pool_context();
709 }
710
711 if ( op ) {
712 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) {
713 if ( oex->oe_key == mdb ) break;
714 }
715 moi = (mdb_op_info *)oex;
716 }
717
718 if ( !moi ) {
719 moi = *moip;
720
721 if ( !moi ) {
722 if ( op ) {
723 moi = op->o_tmpalloc(sizeof(struct mdb_op_info),op->o_tmpmemctx);
724 } else {
725 moi = ch_malloc(sizeof(mdb_op_info));
726 }
727 moi->moi_flag = MOI_FREEIT;
728 *moip = moi;
729 }
730 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
731 moi->moi_oe.oe_key = mdb;
732 moi->moi_ref = 0;
733 moi->moi_txn = NULL;
734 }
735
736 if ( !rdonly ) {
737 /* This op started as a reader, but now wants to write. */
738 if ( moi->moi_flag & MOI_READER ) {
739 moi = *moip;
740 LDAP_SLIST_INSERT_HEAD( &op->o_extra, &moi->moi_oe, oe_next );
741 } else {
742 /* This op is continuing an existing write txn */
743 *moip = moi;
744 }
745 moi->moi_ref++;
746 if ( !moi->moi_txn ) {
747 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) {
748 moi->moi_txn = mdb_tool_txn;
749 } else {
750 int flag = 0;
751 #ifdef SLAP_CONTROL_X_LAZY_COMMIT
752 if ( get_lazyCommit( op ))
753 flag |= MDB_NOMETASYNC;
754 #endif
755 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, flag, &moi->moi_txn );
756 if (rc) {
757 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
758 mdb_strerror(rc), rc );
759 }
760 return rc;
761 }
762 }
763 return 0;
764 }
765
766 /* OK, this is a reader */
767 if ( !moi->moi_txn ) {
768 if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) {
769 moi->moi_txn = mdb_tool_txn;
770 goto ok;
771 }
772 if ( !ctx ) {
773 /* Shouldn't happen unless we're single-threaded */
774 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
775 if (rc) {
776 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
777 mdb_strerror(rc), rc );
778 }
779 return rc;
780 }
781 if ( ldap_pvt_thread_pool_getkey( ctx, mdb->mi_dbenv, &data, NULL ) ) {
782 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &moi->moi_txn );
783 if (rc) {
784 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n",
785 mdb_strerror(rc), rc );
786 return rc;
787 }
788 data = moi->moi_txn;
789 if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, mdb->mi_dbenv,
790 data, mdb_reader_free, NULL, NULL ) ) ) {
791 mdb_txn_abort( moi->moi_txn );
792 moi->moi_txn = NULL;
793 Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: thread_pool_setkey failed err (%d)\n",
794 rc );
795 return rc;
796 }
797 } else {
798 moi->moi_txn = data;
799 renew = 1;
800 }
801 moi->moi_flag |= MOI_READER;
802 }
803 ok:
804 if ( moi->moi_ref < 1 ) {
805 moi->moi_ref = 0;
806 }
807 if ( renew ) {
808 rc = mdb_txn_renew( moi->moi_txn );
809 assert(!rc);
810 }
811 moi->moi_ref++;
812 if ( *moip != moi )
813 *moip = moi;
814
815 return 0;
816 }
817
mdb_txn(Operation * op,int txnop,OpExtra ** ptr)818 int mdb_txn( Operation *op, int txnop, OpExtra **ptr )
819 {
820 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
821 mdb_op_info **moip = (mdb_op_info **)ptr, *moi = *moip;
822 int rc;
823
824 switch( txnop ) {
825 case SLAP_TXN_BEGIN:
826 rc = mdb_opinfo_get( op, mdb, 0, moip );
827 if ( !rc ) {
828 moi = *moip;
829 moi->moi_flag |= MOI_KEEPER;
830 }
831 return rc;
832 case SLAP_TXN_COMMIT:
833 rc = mdb_txn_commit( moi->moi_txn );
834 if ( rc )
835 mdb->mi_numads = 0;
836 op->o_tmpfree( moi, op->o_tmpmemctx );
837 return rc;
838 case SLAP_TXN_ABORT:
839 mdb->mi_numads = 0;
840 mdb_txn_abort( moi->moi_txn );
841 op->o_tmpfree( moi, op->o_tmpmemctx );
842 return 0;
843 }
844 return LDAP_OTHER;
845 }
846
847 /* Count up the sizes of the components of an entry */
mdb_entry_partsize(struct mdb_info * mdb,MDB_txn * txn,Entry * e,Ecount * eh)848 static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e,
849 Ecount *eh)
850 {
851 ber_len_t len, dlen;
852 int i, nat = 0, nval = 0, nnval = 0, doff = 0;
853 Attribute *a;
854 unsigned hi;
855
856 eh->multi = NULL;
857 len = 4*sizeof(int); /* nattrs, nvals, ocflags, offset */
858 dlen = len;
859 for (a=e->e_attrs; a; a=a->a_next) {
860 /* For AttributeDesc, we only store the attr index */
861 nat++;
862 if (a->a_desc->ad_index >= MDB_MAXADS) {
863 Debug( LDAP_DEBUG_ANY, "mdb_entry_partsize: too many AttributeDescriptions used\n" );
864 return LDAP_OTHER;
865 }
866 if (!mdb->mi_adxs[a->a_desc->ad_index]) {
867 int rc = mdb_ad_get(mdb, txn, a->a_desc);
868 if (rc)
869 return rc;
870 }
871 len += 2*sizeof(int); /* AD index, numvals */
872 dlen += 2*sizeof(int);
873 nval += a->a_numvals + 1; /* empty berval at end */
874 mdb_attr_multi_thresh( mdb, a->a_desc, &hi, NULL );
875 if (a->a_numvals > hi)
876 a->a_flags |= SLAP_ATTR_BIG_MULTI;
877 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
878 doff += a->a_numvals;
879 for (i=0; i<a->a_numvals; i++) {
880 int alen = a->a_vals[i].bv_len + 1 + sizeof(int); /* len */
881 len += alen;
882 if (a->a_flags & SLAP_ATTR_BIG_MULTI) {
883 if (!eh->multi)
884 eh->multi = a;
885 } else {
886 dlen += alen;
887 }
888 }
889 if (a->a_nvals != a->a_vals) {
890 nval += a->a_numvals + 1;
891 nnval++;
892 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
893 doff += a->a_numvals;
894 for (i=0; i<a->a_numvals; i++) {
895 int alen = a->a_nvals[i].bv_len + 1 + sizeof(int);
896 len += alen;
897 if (!(a->a_flags & SLAP_ATTR_BIG_MULTI))
898 dlen += alen;
899 }
900 }
901 }
902 /* padding */
903 dlen = (dlen + sizeof(ID)-1) & ~(sizeof(ID)-1);
904 eh->len = len;
905 eh->dlen = dlen;
906 eh->nattrs = nat;
907 eh->nvals = nval;
908 eh->offset = nat + nval - nnval - doff;
909 return 0;
910 }
911
912 /* Flag bits for an encoded attribute */
913 #define MDB_AT_SORTED (1U<<(sizeof(unsigned int)*CHAR_BIT-1))
914 /* the values are in sorted order */
915 #define MDB_AT_MULTI (1<<(sizeof(unsigned int)*CHAR_BIT-2))
916 /* the values of this multi-valued attr are stored separately */
917
918 #define MDB_AT_NVALS (1U<<(sizeof(unsigned int)*CHAR_BIT-1))
919 /* this attribute has normalized values */
920
921 /* Flatten an Entry into a buffer. The buffer starts with the count of the
922 * number of attributes in the entry, the total number of values in the
923 * entry, and the e_ocflags. It then contains a list of integers for each
924 * attribute. For each attribute the first integer gives the index of the
925 * matching AttributeDescription, followed by the number of values in the
926 * attribute. If the MDB_AT_SORTED bit of the attr index is set, the
927 * attribute's values are already sorted. If the MDB_AT_MULTI bit of the
928 * attr index is set, the values are stored separately.
929 *
930 * If the MDB_AT_NVALS bit of numvals is set, the attribute also has
931 * normalized values present. (Note - a_numvals is an unsigned int, so this
932 * means it's possible to receive an attribute that we can't encode due
933 * to size overflow. In practice, this should not be an issue.)
934 *
935 * Then the length of each value is listed. If there are normalized values,
936 * their lengths come next. This continues for each attribute. After all
937 * of the lengths for the last attribute, the actual values are copied,
938 * with a NUL terminator after each value.
939 * The buffer is padded to the sizeof(ID). The entire buffer size is
940 * precomputed so that a single malloc can be performed.
941 */
mdb_entry_encode(Operation * op,Entry * e,MDB_val * data,Ecount * eh)942 static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh)
943 {
944 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
945 ber_len_t i;
946 Attribute *a;
947 unsigned char *ptr;
948 unsigned int *lp, l;
949
950 Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_encode(0x%08lx): %s\n",
951 (long) e->e_id, e->e_dn );
952
953 /* make sure e->e_ocflags is set */
954 if (is_entry_referral(e))
955 ; /* empty */
956
957 lp = (unsigned int *)data->mv_data;
958 *lp++ = eh->nattrs;
959 *lp++ = eh->nvals;
960 *lp++ = (unsigned int)e->e_ocflags;
961 *lp++ = eh->offset;
962 ptr = (unsigned char *)(lp + eh->offset);
963
964 for (a=e->e_attrs; a; a=a->a_next) {
965 if (!a->a_desc->ad_index)
966 return LDAP_UNDEFINED_TYPE;
967 l = mdb->mi_adxs[a->a_desc->ad_index];
968 if (a->a_flags & SLAP_ATTR_BIG_MULTI)
969 l |= MDB_AT_MULTI;
970 if (a->a_flags & SLAP_ATTR_SORTED_VALS)
971 l |= MDB_AT_SORTED;
972 *lp++ = l;
973 l = a->a_numvals;
974 if (a->a_nvals != a->a_vals)
975 l |= MDB_AT_NVALS;
976 *lp++ = l;
977 if (a->a_flags & SLAP_ATTR_BIG_MULTI) {
978 continue;
979 } else {
980 if (a->a_vals) {
981 for (i=0; a->a_vals[i].bv_val; i++);
982 assert( i == a->a_numvals );
983 for (i=0; i<a->a_numvals; i++) {
984 *lp++ = a->a_vals[i].bv_len;
985 memcpy(ptr, a->a_vals[i].bv_val,
986 a->a_vals[i].bv_len);
987 ptr += a->a_vals[i].bv_len;
988 *ptr++ = '\0';
989 }
990 if (a->a_nvals != a->a_vals) {
991 for (i=0; i<a->a_numvals; i++) {
992 *lp++ = a->a_nvals[i].bv_len;
993 memcpy(ptr, a->a_nvals[i].bv_val,
994 a->a_nvals[i].bv_len);
995 ptr += a->a_nvals[i].bv_len;
996 *ptr++ = '\0';
997 }
998 }
999 }
1000 }
1001 }
1002
1003 Debug( LDAP_DEBUG_TRACE, "<= mdb_entry_encode(0x%08lx): %s\n",
1004 (long) e->e_id, e->e_dn );
1005
1006 return 0;
1007 }
1008
1009 /* Retrieve an Entry that was stored using entry_encode above.
1010 *
1011 * Note: everything is stored in a single contiguous block, so
1012 * you can not free individual attributes or names from this
1013 * structure. Attempting to do so will likely corrupt memory.
1014 */
1015
mdb_entry_decode(Operation * op,MDB_txn * txn,MDB_val * data,ID id,Entry ** e)1016 int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, ID id, Entry **e)
1017 {
1018 struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
1019 int i, j, nattrs, nvals;
1020 int rc;
1021 Attribute *a;
1022 Entry *x;
1023 const char *text;
1024 unsigned int *lp = (unsigned int *)data->mv_data;
1025 unsigned char *ptr;
1026 BerVarray bptr;
1027 MDB_cursor *mvc = NULL;
1028
1029 Debug( LDAP_DEBUG_TRACE,
1030 "=> mdb_entry_decode:\n" );
1031
1032 nattrs = *lp++;
1033 nvals = *lp++;
1034 x = mdb_entry_alloc(op, nattrs, nvals);
1035 x->e_ocflags = *lp++;
1036 if (!nvals) {
1037 goto done;
1038 }
1039 a = x->e_attrs;
1040 bptr = a->a_vals;
1041 i = *lp++;
1042 ptr = (unsigned char *)(lp + i);
1043
1044 for (;nattrs>0; nattrs--) {
1045 int have_nval = 0, multi = 0;
1046 a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS;
1047 i = *lp++;
1048 if (i & MDB_AT_SORTED) {
1049 i ^= MDB_AT_SORTED;
1050 a->a_flags |= SLAP_ATTR_SORTED_VALS;
1051 }
1052 if (i & MDB_AT_MULTI) {
1053 i ^= MDB_AT_MULTI;
1054 a->a_flags |= SLAP_ATTR_BIG_MULTI;
1055 multi = 1;
1056 }
1057 if (i > mdb->mi_numads) {
1058 rc = mdb_ad_read(mdb, txn);
1059 if (rc)
1060 goto leave;
1061 if (i > mdb->mi_numads) {
1062 Debug( LDAP_DEBUG_ANY,
1063 "mdb_entry_decode: attribute index %d not recognized\n",
1064 i );
1065 rc = LDAP_OTHER;
1066 goto leave;
1067 }
1068 }
1069 a->a_desc = mdb->mi_ads[i];
1070 a->a_numvals = *lp++;
1071 if (a->a_numvals & MDB_AT_NVALS) {
1072 a->a_numvals ^= MDB_AT_NVALS;
1073 have_nval = 1;
1074 }
1075 a->a_vals = bptr;
1076 if (multi) {
1077 if (!mvc) {
1078 rc = mdb_cursor_open(txn, mdb->mi_dbis[MDB_ID2VAL], &mvc);
1079 if (rc)
1080 goto leave;
1081 }
1082 i = a->a_numvals;
1083 mdb_mval_get(op, mvc, id, a, have_nval);
1084 bptr += i + 1;
1085 if (have_nval)
1086 bptr += i + 1;
1087 } else {
1088 for (i=0; i<a->a_numvals; i++) {
1089 bptr->bv_len = *lp++;
1090 bptr->bv_val = (char *)ptr;
1091 ptr += bptr->bv_len+1;
1092 bptr++;
1093 }
1094 bptr->bv_val = NULL;
1095 bptr->bv_len = 0;
1096 bptr++;
1097
1098 if (have_nval) {
1099 a->a_nvals = bptr;
1100 for (i=0; i<a->a_numvals; i++) {
1101 bptr->bv_len = *lp++;
1102 bptr->bv_val = (char *)ptr;
1103 ptr += bptr->bv_len+1;
1104 bptr++;
1105 }
1106 bptr->bv_val = NULL;
1107 bptr->bv_len = 0;
1108 bptr++;
1109 } else {
1110 a->a_nvals = a->a_vals;
1111 }
1112 }
1113
1114 /* FIXME: This is redundant once a sorted entry is saved into the DB */
1115 if (( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL )
1116 && !(a->a_flags & SLAP_ATTR_SORTED_VALS)) {
1117 rc = slap_sort_vals( (Modifications *)a, &text, &j, NULL );
1118 if ( rc == LDAP_SUCCESS ) {
1119 a->a_flags |= SLAP_ATTR_SORTED_VALS;
1120 } else if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
1121 /* should never happen */
1122 Debug( LDAP_DEBUG_ANY,
1123 "mdb_entry_decode: attributeType %s value #%d provided more than once\n",
1124 a->a_desc->ad_cname.bv_val, j );
1125 goto leave;
1126 }
1127 }
1128 a->a_next = a+1;
1129 a = a->a_next;
1130 }
1131 a[-1].a_next = NULL;
1132 done:
1133 Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n" );
1134 *e = x;
1135 rc = 0;
1136
1137 leave:
1138 if (mvc)
1139 mdb_cursor_close(mvc);
1140 return rc;
1141 }
1142