1/*	$NetBSD: compare.c,v 1.1.1.3 2010/12/12 15:22:54 adam Exp $	*/
2
3/* compare.c - bdb backend compare routine */
4/* OpenLDAP: pkg/ldap/servers/slapd/back-bdb/compare.c,v 1.51.2.8 2010/04/13 20:23:23 kurt Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2000-2010 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 "portable.h"
20
21#include <stdio.h>
22#include <ac/string.h>
23
24#include "back-bdb.h"
25
26int
27bdb_compare( Operation *op, SlapReply *rs )
28{
29	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
30	Entry		*e = NULL;
31	EntryInfo	*ei;
32	Attribute	*a;
33	int		manageDSAit = get_manageDSAit( op );
34
35	DB_TXN		*rtxn;
36	DB_LOCK		lock;
37
38	rs->sr_err = bdb_reader_get(op, bdb->bi_dbenv, &rtxn);
39	switch(rs->sr_err) {
40	case 0:
41		break;
42	default:
43		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
44		return rs->sr_err;
45	}
46
47dn2entry_retry:
48	/* get entry */
49	rs->sr_err = bdb_dn2entry( op, rtxn, &op->o_req_ndn, &ei, 1,
50		&lock );
51
52	switch( rs->sr_err ) {
53	case DB_NOTFOUND:
54	case 0:
55		break;
56	case LDAP_BUSY:
57		rs->sr_text = "ldap server busy";
58		goto return_results;
59	case DB_LOCK_DEADLOCK:
60	case DB_LOCK_NOTGRANTED:
61		goto dn2entry_retry;
62	default:
63		rs->sr_err = LDAP_OTHER;
64		rs->sr_text = "internal error";
65		goto return_results;
66	}
67
68	e = ei->bei_e;
69	if ( rs->sr_err == DB_NOTFOUND ) {
70		if ( e != NULL ) {
71			/* return referral only if "disclose" is granted on the object */
72			if ( ! access_allowed( op, e, slap_schema.si_ad_entry,
73				NULL, ACL_DISCLOSE, NULL ) )
74			{
75				rs->sr_err = LDAP_NO_SUCH_OBJECT;
76
77			} else {
78				rs->sr_matched = ch_strdup( e->e_dn );
79				rs->sr_ref = is_entry_referral( e )
80					? get_entry_referrals( op, e )
81					: NULL;
82				rs->sr_err = LDAP_REFERRAL;
83			}
84
85			bdb_cache_return_entry_r( bdb, e, &lock );
86			e = NULL;
87
88		} else {
89			rs->sr_ref = referral_rewrite( default_referral,
90				NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
91			rs->sr_err = rs->sr_ref ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
92		}
93
94		send_ldap_result( op, rs );
95
96		ber_bvarray_free( rs->sr_ref );
97		free( (char *)rs->sr_matched );
98		rs->sr_ref = NULL;
99		rs->sr_matched = NULL;
100
101		goto done;
102	}
103
104	if (!manageDSAit && is_entry_referral( e ) ) {
105		/* return referral only if "disclose" is granted on the object */
106		if ( !access_allowed( op, e, slap_schema.si_ad_entry,
107			NULL, ACL_DISCLOSE, NULL ) )
108		{
109			rs->sr_err = LDAP_NO_SUCH_OBJECT;
110		} else {
111			/* entry is a referral, don't allow compare */
112			rs->sr_ref = get_entry_referrals( op, e );
113			rs->sr_err = LDAP_REFERRAL;
114			rs->sr_matched = e->e_name.bv_val;
115		}
116
117		Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 );
118
119		send_ldap_result( op, rs );
120
121		ber_bvarray_free( rs->sr_ref );
122		rs->sr_ref = NULL;
123		rs->sr_matched = NULL;
124		goto done;
125	}
126
127	if ( get_assert( op ) &&
128		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
129	{
130		if ( !access_allowed( op, e, slap_schema.si_ad_entry,
131			NULL, ACL_DISCLOSE, NULL ) )
132		{
133			rs->sr_err = LDAP_NO_SUCH_OBJECT;
134		} else {
135			rs->sr_err = LDAP_ASSERTION_FAILED;
136		}
137		goto return_results;
138	}
139
140	if ( !access_allowed( op, e, op->oq_compare.rs_ava->aa_desc,
141		&op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL ) )
142	{
143		/* return error only if "disclose"
144		 * is granted on the object */
145		if ( !access_allowed( op, e, slap_schema.si_ad_entry,
146					NULL, ACL_DISCLOSE, NULL ) )
147		{
148			rs->sr_err = LDAP_NO_SUCH_OBJECT;
149		} else {
150			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
151		}
152		goto return_results;
153	}
154
155	rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
156
157	for ( a = attrs_find( e->e_attrs, op->oq_compare.rs_ava->aa_desc );
158		a != NULL;
159		a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) )
160	{
161		rs->sr_err = LDAP_COMPARE_FALSE;
162
163		if ( attr_valfind( a,
164			SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
165				SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
166			&op->oq_compare.rs_ava->aa_value, NULL,
167			op->o_tmpmemctx ) == 0 )
168		{
169			rs->sr_err = LDAP_COMPARE_TRUE;
170			break;
171		}
172	}
173
174return_results:
175	send_ldap_result( op, rs );
176
177	switch ( rs->sr_err ) {
178	case LDAP_COMPARE_FALSE:
179	case LDAP_COMPARE_TRUE:
180		rs->sr_err = LDAP_SUCCESS;
181		break;
182	}
183
184done:
185	/* free entry */
186	if ( e != NULL ) {
187		bdb_cache_return_entry_r( bdb, e, &lock );
188	}
189
190	return rs->sr_err;
191}
192