1/* compare.c - bdb backend compare routine */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2000-2011 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
22#include "back-bdb.h"
23
24int
25bdb_compare( Operation *op, SlapReply *rs )
26{
27	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
28	Entry		*e = NULL;
29	EntryInfo	*ei;
30	int		manageDSAit = get_manageDSAit( op );
31
32	DB_TXN		*rtxn;
33	DB_LOCK		lock;
34
35	rs->sr_err = bdb_reader_get(op, bdb->bi_dbenv, &rtxn);
36	switch(rs->sr_err) {
37	case 0:
38		break;
39	default:
40		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
41		return rs->sr_err;
42	}
43
44dn2entry_retry:
45	/* get entry */
46	rs->sr_err = bdb_dn2entry( op, rtxn, &op->o_req_ndn, &ei, 1,
47		&lock );
48
49	switch( rs->sr_err ) {
50	case DB_NOTFOUND:
51	case 0:
52		break;
53	case LDAP_BUSY:
54		rs->sr_text = "ldap server busy";
55		goto return_results;
56	case DB_LOCK_DEADLOCK:
57	case DB_LOCK_NOTGRANTED:
58		goto dn2entry_retry;
59	default:
60		rs->sr_err = LDAP_OTHER;
61		rs->sr_text = "internal error";
62		goto return_results;
63	}
64
65	e = ei->bei_e;
66	if ( rs->sr_err == DB_NOTFOUND ) {
67		if ( e != NULL ) {
68			/* return referral only if "disclose" is granted on the object */
69			if ( ! access_allowed( op, e, slap_schema.si_ad_entry,
70				NULL, ACL_DISCLOSE, NULL ) )
71			{
72				rs->sr_err = LDAP_NO_SUCH_OBJECT;
73
74			} else {
75				rs->sr_matched = ch_strdup( e->e_dn );
76				rs->sr_ref = is_entry_referral( e )
77					? get_entry_referrals( op, e )
78					: NULL;
79				rs->sr_err = LDAP_REFERRAL;
80			}
81
82			bdb_cache_return_entry_r( bdb, e, &lock );
83			e = NULL;
84
85		} else {
86			rs->sr_ref = referral_rewrite( default_referral,
87				NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
88			rs->sr_err = rs->sr_ref ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
89		}
90
91		send_ldap_result( op, rs );
92
93		ber_bvarray_free( rs->sr_ref );
94		free( (char *)rs->sr_matched );
95		rs->sr_ref = NULL;
96		rs->sr_matched = NULL;
97
98		goto done;
99	}
100
101	if (!manageDSAit && is_entry_referral( e ) ) {
102		/* return referral only if "disclose" is granted on the object */
103		if ( !access_allowed( op, e, slap_schema.si_ad_entry,
104			NULL, ACL_DISCLOSE, NULL ) )
105		{
106			rs->sr_err = LDAP_NO_SUCH_OBJECT;
107		} else {
108			/* entry is a referral, don't allow compare */
109			rs->sr_ref = get_entry_referrals( op, e );
110			rs->sr_err = LDAP_REFERRAL;
111			rs->sr_matched = e->e_name.bv_val;
112		}
113
114		Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 );
115
116		send_ldap_result( op, rs );
117
118		ber_bvarray_free( rs->sr_ref );
119		rs->sr_ref = NULL;
120		rs->sr_matched = NULL;
121		goto done;
122	}
123
124	rs->sr_err = slap_compare_entry( op, e, op->orc_ava );
125
126return_results:
127	send_ldap_result( op, rs );
128
129	switch ( rs->sr_err ) {
130	case LDAP_COMPARE_FALSE:
131	case LDAP_COMPARE_TRUE:
132		rs->sr_err = LDAP_SUCCESS;
133		break;
134	}
135
136done:
137	/* free entry */
138	if ( e != NULL ) {
139		bdb_cache_return_entry_r( bdb, e, &lock );
140	}
141
142	return rs->sr_err;
143}
144