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