xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-ndb/compare.cpp (revision e670fd5c413e99c2f6a37901bb21c537fcd322d2)
1 /* compare.cpp - ndb backend compare routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2008-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 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by Howard Chu for inclusion
18  * in OpenLDAP Software. This work was sponsored by MySQL.
19  */
20 
21 #include "portable.h"
22 
23 #include <stdio.h>
24 #include <ac/string.h>
25 
26 #include "back-ndb.h"
27 
28 int
ndb_back_compare(Operation * op,SlapReply * rs)29 ndb_back_compare( Operation *op, SlapReply *rs )
30 {
31 	struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
32 	Entry		e = {0};
33 	Attribute	*a;
34 	int		manageDSAit = get_manageDSAit( op );
35 
36 	NdbArgs NA;
37 	NdbRdns rdns;
38 	struct berval matched;
39 
40 	/* Get our NDB handle */
41 	rs->sr_err = ndb_thread_handle( op, &NA.ndb );
42 
43 	rdns.nr_num = 0;
44 	NA.rdns = &rdns;
45 	e.e_name = op->o_req_dn;
46 	e.e_nname = op->o_req_ndn;
47 	NA.e = &e;
48 
49 dn2entry_retry:
50 	NA.txn = NA.ndb->startTransaction();
51 	rs->sr_text = NULL;
52 	if( !NA.txn ) {
53 		Debug( LDAP_DEBUG_TRACE,
54 			LDAP_XSTRING(ndb_compare) ": startTransaction failed: %s (%d)\n",
55 			NA.ndb->getNdbError().message, NA.ndb->getNdbError().code, 0 );
56 		rs->sr_err = LDAP_OTHER;
57 		rs->sr_text = "internal error";
58 		goto return_results;
59 	}
60 
61 	NA.ocs = NULL;
62 	/* get entry */
63 	rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
64 	switch( rs->sr_err ) {
65 	case 0:
66 		break;
67 	case LDAP_NO_SUCH_OBJECT:
68 		rs->sr_matched = matched.bv_val;
69 		if ( NA.ocs )
70 			ndb_check_referral( op, rs, &NA );
71 		goto return_results;
72 	case LDAP_BUSY:
73 		rs->sr_text = "ldap server busy";
74 		goto return_results;
75 #if 0
76 	case DB_LOCK_DEADLOCK:
77 	case DB_LOCK_NOTGRANTED:
78 		goto dn2entry_retry;
79 #endif
80 	default:
81 		rs->sr_err = LDAP_OTHER;
82 		rs->sr_text = "internal error";
83 		goto return_results;
84 	}
85 
86 	rs->sr_err = ndb_entry_get_data( op, &NA, 0 );
87 	ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
88 	if (!manageDSAit && is_entry_referral( &e ) ) {
89 		/* return referral only if "disclose" is granted on the object */
90 		if ( !access_allowed( op, &e, slap_schema.si_ad_entry,
91 			NULL, ACL_DISCLOSE, NULL ) )
92 		{
93 			rs->sr_err = LDAP_NO_SUCH_OBJECT;
94 		} else {
95 			/* entry is a referral, don't allow compare */
96 			rs->sr_ref = get_entry_referrals( op, &e );
97 			rs->sr_err = LDAP_REFERRAL;
98 			rs->sr_matched = e.e_name.bv_val;
99 			rs->sr_flags |= REP_REF_MUSTBEFREED;
100 		}
101 
102 		Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0, 0, 0 );
103 		goto return_results;
104 	}
105 
106 	if ( get_assert( op ) &&
107 		( test_filter( op, &e, (Filter *)get_assertion( op )) != LDAP_COMPARE_TRUE ))
108 	{
109 		if ( !access_allowed( op, &e, slap_schema.si_ad_entry,
110 			NULL, ACL_DISCLOSE, NULL ) )
111 		{
112 			rs->sr_err = LDAP_NO_SUCH_OBJECT;
113 		} else {
114 			rs->sr_err = LDAP_ASSERTION_FAILED;
115 		}
116 		goto return_results;
117 	}
118 
119 	if ( !access_allowed( op, &e, op->oq_compare.rs_ava->aa_desc,
120 		&op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL ) )
121 	{
122 		/* return error only if "disclose"
123 		 * is granted on the object */
124 		if ( !access_allowed( op, &e, slap_schema.si_ad_entry,
125 					NULL, ACL_DISCLOSE, NULL ) )
126 		{
127 			rs->sr_err = LDAP_NO_SUCH_OBJECT;
128 		} else {
129 			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
130 		}
131 		goto return_results;
132 	}
133 
134 	rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
135 
136 	for ( a = attrs_find( e.e_attrs, op->oq_compare.rs_ava->aa_desc );
137 		a != NULL;
138 		a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc ) )
139 	{
140 		rs->sr_err = LDAP_COMPARE_FALSE;
141 
142 		if ( attr_valfind( a,
143 			SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
144 				SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
145 			&op->oq_compare.rs_ava->aa_value, NULL,
146 			op->o_tmpmemctx ) == 0 )
147 		{
148 			rs->sr_err = LDAP_COMPARE_TRUE;
149 			break;
150 		}
151 	}
152 
153 return_results:
154 	NA.txn->close();
155 	if ( e.e_attrs ) {
156 		attrs_free( e.e_attrs );
157 		e.e_attrs = NULL;
158 	}
159 	send_ldap_result( op, rs );
160 
161 	switch ( rs->sr_err ) {
162 	case LDAP_COMPARE_FALSE:
163 	case LDAP_COMPARE_TRUE:
164 		rs->sr_err = LDAP_SUCCESS;
165 		break;
166 	}
167 
168 	return rs->sr_err;
169 }
170