1 /* $OpenLDAP: pkg/ldap/servers/slapd/compare.c,v 1.136.2.8 2008/02/11 23:26:43 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
15 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
16 * All rights reserved.
18 * Redistribution and use in source and binary forms are permitted
19 * provided that this notice is preserved and that due credit is given
20 * to the University of Michigan at Ann Arbor. The name of the University
21 * may not be used to endorse or promote products derived from this
22 * software without specific prior written permission. This software
23 * is provided ``as is'' without express or implied warranty.
29 #include <ac/socket.h>
30 #include <ac/string.h>
34 static int compare_entry(
37 AttributeAssertion
*ava
);
44 struct berval dn
= BER_BVNULL
;
45 struct berval desc
= BER_BVNULL
;
46 struct berval value
= BER_BVNULL
;
47 AttributeAssertion ava
= ATTRIBUTEASSERTION_INIT
;
49 Debug( LDAP_DEBUG_TRACE
, "%s do_compare\n",
50 op
->o_log_prefix
, 0, 0 );
52 * Parse the compare request. It looks like this:
54 * CompareRequest := [APPLICATION 14] SEQUENCE {
55 * entry DistinguishedName,
58 * value AttributeValue
63 if ( ber_scanf( op
->o_ber
, "{m" /*}*/, &dn
) == LBER_ERROR
) {
64 Debug( LDAP_DEBUG_ANY
, "%s do_compare: ber_scanf failed\n",
65 op
->o_log_prefix
, 0, 0 );
66 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding error" );
67 return SLAPD_DISCONNECT
;
70 if ( ber_scanf( op
->o_ber
, "{mm}", &desc
, &value
) == LBER_ERROR
) {
71 Debug( LDAP_DEBUG_ANY
, "%s do_compare: get ava failed\n",
72 op
->o_log_prefix
, 0, 0 );
73 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding error" );
74 return SLAPD_DISCONNECT
;
77 if ( ber_scanf( op
->o_ber
, /*{*/ "}" ) == LBER_ERROR
) {
78 Debug( LDAP_DEBUG_ANY
, "%s do_compare: ber_scanf failed\n",
79 op
->o_log_prefix
, 0, 0 );
80 send_ldap_discon( op
, rs
, LDAP_PROTOCOL_ERROR
, "decoding error" );
81 return SLAPD_DISCONNECT
;
84 if( get_ctrls( op
, rs
, 1 ) != LDAP_SUCCESS
) {
85 Debug( LDAP_DEBUG_ANY
, "%s do_compare: get_ctrls failed\n",
86 op
->o_log_prefix
, 0, 0 );
90 rs
->sr_err
= dnPrettyNormal( NULL
, &dn
, &op
->o_req_dn
, &op
->o_req_ndn
,
92 if( rs
->sr_err
!= LDAP_SUCCESS
) {
93 Debug( LDAP_DEBUG_ANY
, "%s do_compare: invalid dn (%s)\n",
94 op
->o_log_prefix
, dn
.bv_val
, 0 );
95 send_ldap_error( op
, rs
, LDAP_INVALID_DN_SYNTAX
, "invalid DN" );
99 Statslog( LDAP_DEBUG_STATS
,
100 "%s CMP dn=\"%s\" attr=\"%s\"\n",
101 op
->o_log_prefix
, op
->o_req_dn
.bv_val
,
104 rs
->sr_err
= slap_bv2ad( &desc
, &ava
.aa_desc
, &rs
->sr_text
);
105 if( rs
->sr_err
!= LDAP_SUCCESS
) {
106 rs
->sr_err
= slap_bv2undef_ad( &desc
, &ava
.aa_desc
,
108 SLAP_AD_PROXIED
|SLAP_AD_NOINSERT
);
109 if( rs
->sr_err
!= LDAP_SUCCESS
) {
110 send_ldap_result( op
, rs
);
115 rs
->sr_err
= asserted_value_validate_normalize( ava
.aa_desc
,
116 ava
.aa_desc
->ad_type
->sat_equality
,
117 SLAP_MR_EQUALITY
|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX
,
118 &value
, &ava
.aa_value
, &rs
->sr_text
, op
->o_tmpmemctx
);
119 if( rs
->sr_err
!= LDAP_SUCCESS
) {
120 send_ldap_result( op
, rs
);
126 Debug( LDAP_DEBUG_ARGS
,
127 "do_compare: dn (%s) attr (%s) value (%s)\n",
129 ava
.aa_desc
->ad_cname
.bv_val
, ava
.aa_value
.bv_val
);
131 op
->o_bd
= frontendDB
;
132 rs
->sr_err
= frontendDB
->be_compare( op
, rs
);
135 op
->o_tmpfree( op
->o_req_dn
.bv_val
, op
->o_tmpmemctx
);
136 op
->o_tmpfree( op
->o_req_ndn
.bv_val
, op
->o_tmpmemctx
);
137 if ( !BER_BVISNULL( &ava
.aa_value
) ) {
138 op
->o_tmpfree( ava
.aa_value
.bv_val
, op
->o_tmpmemctx
);
145 fe_op_compare( Operation
*op
, SlapReply
*rs
)
148 AttributeAssertion
*ava
= op
->orc_ava
;
149 BackendDB
*bd
= op
->o_bd
;
151 if( strcasecmp( op
->o_req_ndn
.bv_val
, LDAP_ROOT_DSE
) == 0 ) {
152 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
153 send_ldap_result( op
, rs
);
157 rs
->sr_err
= root_dse_info( op
->o_conn
, &entry
, &rs
->sr_text
);
158 if( rs
->sr_err
!= LDAP_SUCCESS
) {
159 send_ldap_result( op
, rs
);
163 } else if ( bvmatch( &op
->o_req_ndn
, &frontendDB
->be_schemandn
) ) {
164 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
165 send_ldap_result( op
, rs
);
170 rs
->sr_err
= schema_info( &entry
, &rs
->sr_text
);
171 if( rs
->sr_err
!= LDAP_SUCCESS
) {
172 send_ldap_result( op
, rs
);
179 rs
->sr_err
= compare_entry( op
, entry
, ava
);
182 send_ldap_result( op
, rs
);
184 if( rs
->sr_err
== LDAP_COMPARE_TRUE
||
185 rs
->sr_err
== LDAP_COMPARE_FALSE
)
187 rs
->sr_err
= LDAP_SUCCESS
;
194 * We could be serving multiple database backends. Select the
195 * appropriate one, or send a referral to our "referral server"
196 * if we don't hold it.
198 op
->o_bd
= select_backend( &op
->o_req_ndn
, 0 );
199 if ( op
->o_bd
== NULL
) {
200 rs
->sr_ref
= referral_rewrite( default_referral
,
201 NULL
, &op
->o_req_dn
, LDAP_SCOPE_DEFAULT
);
203 rs
->sr_err
= LDAP_REFERRAL
;
204 if (!rs
->sr_ref
) rs
->sr_ref
= default_referral
;
206 send_ldap_result( op
, rs
);
208 if (rs
->sr_ref
!= default_referral
) ber_bvarray_free( rs
->sr_ref
);
213 /* check restrictions */
214 if( backend_check_restrictions( op
, rs
, NULL
) != LDAP_SUCCESS
) {
215 send_ldap_result( op
, rs
);
219 /* check for referrals */
220 if( backend_check_referrals( op
, rs
) != LDAP_SUCCESS
) {
224 if ( SLAP_SHADOW(op
->o_bd
) && get_dontUseCopy(op
) ) {
225 /* don't use shadow copy */
226 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
229 } else if ( ava
->aa_desc
== slap_schema
.si_ad_entryDN
) {
230 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
231 "entryDN compare not supported" );
233 } else if ( ava
->aa_desc
== slap_schema
.si_ad_subschemaSubentry
) {
234 send_ldap_error( op
, rs
, LDAP_UNWILLING_TO_PERFORM
,
235 "subschemaSubentry compare not supported" );
237 #ifndef SLAP_COMPARE_IN_FRONTEND
238 } else if ( ava
->aa_desc
== slap_schema
.si_ad_hasSubordinates
239 && op
->o_bd
->be_has_subordinates
)
241 int rc
, hasSubordinates
= LDAP_SUCCESS
;
243 rc
= be_entry_get_rw( op
, &op
->o_req_ndn
, NULL
, NULL
, 0, &entry
);
244 if ( rc
== 0 && entry
) {
245 if ( ! access_allowed( op
, entry
,
246 ava
->aa_desc
, &ava
->aa_value
, ACL_COMPARE
, NULL
) )
248 rc
= rs
->sr_err
= LDAP_INSUFFICIENT_ACCESS
;
251 rc
= rs
->sr_err
= op
->o_bd
->be_has_subordinates( op
,
252 entry
, &hasSubordinates
);
253 be_entry_release_r( op
, entry
);
260 asserted
= bvmatch( &ava
->aa_value
, &slap_true_bv
)
261 ? LDAP_COMPARE_TRUE
: LDAP_COMPARE_FALSE
;
262 if ( hasSubordinates
== asserted
) {
263 rs
->sr_err
= LDAP_COMPARE_TRUE
;
266 rs
->sr_err
= LDAP_COMPARE_FALSE
;
270 /* return error only if "disclose"
271 * is granted on the object */
272 if ( backend_access( op
, NULL
, &op
->o_req_ndn
,
273 slap_schema
.si_ad_entry
,
274 NULL
, ACL_DISCLOSE
, NULL
) == LDAP_INSUFFICIENT_ACCESS
)
276 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
280 send_ldap_result( op
, rs
);
283 rs
->sr_err
= LDAP_SUCCESS
;
286 } else if ( op
->o_bd
->be_compare
) {
287 rs
->sr_err
= op
->o_bd
->be_compare( op
, rs
);
289 #endif /* ! SLAP_COMPARE_IN_FRONTEND */
291 rs
->sr_err
= SLAP_CB_CONTINUE
;
294 if ( rs
->sr_err
== SLAP_CB_CONTINUE
) {
295 /* do our best to compare that AVA
297 * NOTE: this code is used only
298 * if SLAP_COMPARE_IN_FRONTEND
299 * is #define'd (it's not by default)
300 * or if op->o_bd->be_compare is NULL.
302 * FIXME: one potential issue is that
303 * if SLAP_COMPARE_IN_FRONTEND overlays
304 * are not executed for compare. */
305 BerVarray vals
= NULL
;
308 rs
->sr_err
= backend_attribute( op
, NULL
, &op
->o_req_ndn
,
309 ava
->aa_desc
, &vals
, ACL_COMPARE
);
310 switch ( rs
->sr_err
) {
312 /* return error only if "disclose"
313 * is granted on the object */
314 if ( backend_access( op
, NULL
, &op
->o_req_ndn
,
315 slap_schema
.si_ad_entry
,
316 NULL
, ACL_DISCLOSE
, NULL
)
317 == LDAP_INSUFFICIENT_ACCESS
)
319 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
324 if ( value_find_ex( op
->oq_compare
.rs_ava
->aa_desc
,
325 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH
|
326 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
,
327 vals
, &ava
->aa_value
, op
->o_tmpmemctx
) == 0 )
329 rs
->sr_err
= LDAP_COMPARE_TRUE
;
333 rs
->sr_err
= LDAP_COMPARE_FALSE
;
339 send_ldap_result( op
, rs
);
342 rs
->sr_err
= LDAP_SUCCESS
;
346 ber_bvarray_free_x( vals
, op
->o_tmpmemctx
);
355 static int compare_entry(
358 AttributeAssertion
*ava
)
360 int rc
= LDAP_COMPARE_FALSE
;
363 if ( ! access_allowed( op
, e
,
364 ava
->aa_desc
, &ava
->aa_value
, ACL_COMPARE
, NULL
) )
366 rc
= LDAP_INSUFFICIENT_ACCESS
;
370 a
= attrs_find( e
->e_attrs
, ava
->aa_desc
);
372 rc
= LDAP_NO_SUCH_ATTRIBUTE
;
376 for(a
= attrs_find( e
->e_attrs
, ava
->aa_desc
);
378 a
= attrs_find( a
->a_next
, ava
->aa_desc
))
380 if (( ava
->aa_desc
!= a
->a_desc
) && ! access_allowed( op
,
381 e
, a
->a_desc
, &ava
->aa_value
, ACL_COMPARE
, NULL
) )
383 rc
= LDAP_INSUFFICIENT_ACCESS
;
387 if ( attr_valfind( a
,
388 SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH
|
389 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH
,
390 &ava
->aa_value
, NULL
, op
->o_tmpmemctx
) == 0 )
392 rc
= LDAP_COMPARE_TRUE
;
398 if( rc
!= LDAP_COMPARE_TRUE
&& rc
!= LDAP_COMPARE_FALSE
) {
399 if ( ! access_allowed( op
, e
,
400 slap_schema
.si_ad_entry
, NULL
, ACL_DISCLOSE
, NULL
) )
402 rc
= LDAP_NO_SUCH_OBJECT
;