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