xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-mdb/id2entry.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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