]> git.sur5r.net Git - openldap/blob - servers/slapd/compare.c
2bffeafbde6fbdcab0c0c31239cbec94b0fde696
[openldap] / servers / slapd / compare.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1995 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21 #include <ac/socket.h>
22
23 #include "ldap_pvt.h"
24 #include "slap.h"
25 #ifdef LDAP_SLAPI
26 #include "slapi.h"
27 #endif
28
29 static int compare_entry(
30         Operation *op,
31         Entry *e,
32         AttributeAssertion *ava );
33
34 int
35 do_compare(
36     Operation   *op,
37     SlapReply   *rs
38 )
39 {
40         Entry *entry = NULL;
41         Entry *fentry = NULL;
42         struct berval dn = { 0, NULL };
43         struct berval desc = { 0, NULL };
44         struct berval value = { 0, NULL };
45         AttributeAssertion ava = { NULL, { 0, NULL } };
46         Backend *be;
47         int manageDSAit;
48
49 #ifdef LDAP_SLAPI
50         Slapi_PBlock *pb = op->o_pb;
51 #endif
52
53         ava.aa_desc = NULL;
54
55 #ifdef NEW_LOGGING
56         LDAP_LOG( OPERATION, ENTRY, "do_compare: conn %d\n", op->o_connid, 0, 0 );
57 #else
58         Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
59 #endif
60         /*
61          * Parse the compare request.  It looks like this:
62          *
63          *      CompareRequest := [APPLICATION 14] SEQUENCE {
64          *              entry   DistinguishedName,
65          *              ava     SEQUENCE {
66          *                      type    AttributeType,
67          *                      value   AttributeValue
68          *              }
69          *      }
70          */
71
72         if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
73 #ifdef NEW_LOGGING
74                 LDAP_LOG( OPERATION, ERR, 
75                         "do_compare: conn %d  ber_scanf failed\n", op->o_connid, 0, 0 );
76 #else
77                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
78 #endif
79                 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
80                 return SLAPD_DISCONNECT;
81         }
82
83         if ( ber_scanf( op->o_ber, "{mm}", &desc, &value ) == LBER_ERROR ) {
84 #ifdef NEW_LOGGING
85                 LDAP_LOG( OPERATION, ERR, 
86                         "do_compare: conn %d  get ava failed\n", op->o_connid, 0, 0 );
87 #else
88                 Debug( LDAP_DEBUG_ANY, "do_compare: get ava failed\n", 0, 0, 0 );
89 #endif
90                 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
91                 return SLAPD_DISCONNECT;
92         }
93
94         if ( ber_scanf( op->o_ber, /*{*/ "}" ) == LBER_ERROR ) {
95 #ifdef NEW_LOGGING
96                 LDAP_LOG( OPERATION, ERR, 
97                         "do_compare: conn %d  ber_scanf failed\n", op->o_connid, 0, 0 );
98 #else
99                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
100 #endif
101                 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
102                 return SLAPD_DISCONNECT;
103         }
104
105         if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
106 #ifdef NEW_LOGGING
107                 LDAP_LOG( OPERATION, INFO, 
108                         "do_compare: conn %d  get_ctrls failed\n", op->o_connid, 0, 0 );
109 #else
110                 Debug( LDAP_DEBUG_ANY, "do_compare: get_ctrls failed\n", 0, 0, 0 );
111 #endif
112                 goto cleanup;
113         } 
114
115         rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn );
116         if( rs->sr_err != LDAP_SUCCESS ) {
117 #ifdef NEW_LOGGING
118                 LDAP_LOG( OPERATION, INFO, 
119                         "do_compare: conn %d  invalid dn (%s)\n",
120                         op->o_connid, dn.bv_val, 0 );
121 #else
122                 Debug( LDAP_DEBUG_ANY,
123                         "do_compare: invalid dn (%s)\n", dn.bv_val, 0, 0 );
124 #endif
125                 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
126                 goto cleanup;
127         }
128
129         rs->sr_err = slap_bv2ad( &desc, &ava.aa_desc, &rs->sr_text );
130         if( rs->sr_err != LDAP_SUCCESS ) {
131                 send_ldap_result( op, rs );
132                 goto cleanup;
133         }
134
135 #ifdef SLAP_NVALUES
136         rs->sr_err = asserted_value_validate_normalize( ava.aa_desc,
137                 ava.aa_desc->ad_type->sat_equality,
138                 SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
139                 &value, &ava.aa_value, &rs->sr_text );
140 #else
141         rs->sr_err = value_validate_normalize( ava.aa_desc, SLAP_MR_EQUALITY,
142                 &value, &ava.aa_value, &rs->sr_text );
143 #endif
144         if( rs->sr_err != LDAP_SUCCESS ) {
145                 send_ldap_result( op, rs );
146                 goto cleanup;
147         }
148
149         if( strcasecmp( op->o_req_ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) {
150 #ifdef NEW_LOGGING
151                 LDAP_LOG( OPERATION, ARGS, 
152                         "do_compare: dn (%s) attr(%s) value (%s)\n",
153                         op->o_req_dn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
154 #else
155                 Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
156                         op->o_req_dn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
157 #endif
158
159                 Statslog( LDAP_DEBUG_STATS,
160                         "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n",
161                         op->o_connid, op->o_opid, op->o_req_dn.bv_val,
162                         ava.aa_desc->ad_cname.bv_val, 0 );
163
164                 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
165                         send_ldap_result( op, rs );
166                         goto cleanup;
167                 }
168
169                 rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text );
170                 if( rs->sr_err != LDAP_SUCCESS ) {
171                         send_ldap_result( op, rs );
172                         goto cleanup;
173                 }
174
175                 fentry = entry;
176
177         } else if ( bvmatch( &op->o_req_ndn, &global_schemandn ) ) {
178 #ifdef NEW_LOGGING
179                 LDAP_LOG( OPERATION, ARGS, 
180                         "do_compare: dn (%s) attr(%s) value (%s)\n",
181                         op->o_req_dn.bv_val, ava.aa_desc->ad_cname.bv_val,
182                         ava.aa_value.bv_val );
183 #else
184                 Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
185                         op->o_req_dn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
186 #endif
187
188                 Statslog( LDAP_DEBUG_STATS,
189                         "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n",
190                         op->o_connid, op->o_opid, op->o_req_dn.bv_val,
191                         ava.aa_desc->ad_cname.bv_val, 0 );
192
193                 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
194                         send_ldap_result( op, rs );
195                         rs->sr_err = 0;
196                         goto cleanup;
197                 }
198
199                 rs->sr_err = schema_info( &entry, &rs->sr_text );
200                 if( rs->sr_err != LDAP_SUCCESS ) {
201                         send_ldap_result( op, rs );
202                         rs->sr_err = 0;
203                         goto cleanup;
204                 }
205                 fentry = entry;
206         }
207
208         if( entry ) {
209                 rs->sr_err = compare_entry( op, entry, &ava );
210                 if( fentry) entry_free( fentry );
211
212                 send_ldap_result( op, rs );
213
214                 if( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
215                         rs->sr_err = 0;
216                 }
217
218                 goto cleanup;
219         }
220
221         manageDSAit = get_manageDSAit( op );
222
223         /*
224          * We could be serving multiple database backends.  Select the
225          * appropriate one, or send a referral to our "referral server"
226          * if we don't hold it.
227          */
228         if ( (op->o_bd = select_backend( &op->o_req_ndn, manageDSAit, 0 )) == NULL ) {
229                 rs->sr_ref = referral_rewrite( default_referral,
230                         NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
231
232                 rs->sr_err = LDAP_REFERRAL;
233                 if (!rs->sr_ref) rs->sr_ref = default_referral;
234                 send_ldap_result( op, rs );
235
236                 if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
237                 rs->sr_err = 0;
238                 goto cleanup;
239         }
240
241         /* check restrictions */
242         if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
243                 send_ldap_result( op, rs );
244                 goto cleanup;
245         }
246
247         /* check for referrals */
248         if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
249                 goto cleanup;
250         }
251
252 #ifdef NEW_LOGGING
253         LDAP_LOG( OPERATION, ARGS, 
254                 "do_compare: dn (%s) attr(%s) value (%s)\n",
255                 op->o_req_dn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
256 #else
257         Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
258             op->o_req_dn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
259 #endif
260
261         Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n",
262             op->o_connid, op->o_opid, op->o_req_dn.bv_val,
263                 ava.aa_desc->ad_cname.bv_val, 0 );
264
265 #if defined( LDAP_SLAPI )
266         slapi_x_pblock_set_operation( pb, op );
267         slapi_pblock_set( pb, SLAPI_COMPARE_TARGET, (void *)dn.bv_val );
268         slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)manageDSAit );
269         slapi_pblock_set( pb, SLAPI_COMPARE_TYPE, (void *)desc.bv_val );
270         slapi_pblock_set( pb, SLAPI_COMPARE_VALUE, (void *)&value );
271
272         rs->sr_err = doPluginFNs( op->o_bd, SLAPI_PLUGIN_PRE_COMPARE_FN, pb );
273         if ( rs->sr_err != 0 ) {
274                 /*
275                  * A preoperation plugin failure will abort the
276                  * entire operation.
277                  */
278 #ifdef NEW_LOGGING
279                 LDAP_LOG( OPERATION, INFO, "do_compare: compare preoperation plugin "
280                                 "failed\n", 0, 0, 0);
281 #else
282                 Debug(LDAP_DEBUG_TRACE, "do_compare: compare preoperation plugin "
283                                 "failed.\n", 0, 0, 0);
284 #endif
285                 if ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rs->sr_err ) != 0)
286                         rs->sr_err = LDAP_OTHER;
287                 goto cleanup;
288         }
289 #endif /* defined( LDAP_SLAPI ) */
290
291         if ( op->o_bd->be_compare ) {
292                 op->oq_compare.rs_ava = &ava;
293                 op->o_bd->be_compare( op, rs );
294         } else {
295                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
296                         "operation not supported within namingContext" );
297         }
298
299 #if defined( LDAP_SLAPI )
300         if ( doPluginFNs( op->o_bd, SLAPI_PLUGIN_POST_COMPARE_FN, pb ) != 0 ) {
301 #ifdef NEW_LOGGING
302                 LDAP_LOG( OPERATION, INFO, "do_compare: compare postoperation plugins "
303                                 "failed\n", 0, 0, 0 );
304 #else
305                 Debug(LDAP_DEBUG_TRACE, "do_compare: compare postoperation plugins "
306                                 "failed.\n", 0, 0, 0);
307 #endif
308         }
309 #endif /* defined( LDAP_SLAPI ) */
310
311 cleanup:
312         free( op->o_req_dn.bv_val );
313         free( op->o_req_ndn.bv_val );
314         if ( ava.aa_value.bv_val ) free( ava.aa_value.bv_val );
315
316         return rs->sr_err;
317 }
318
319 static int compare_entry(
320         Operation *op,
321         Entry *e,
322         AttributeAssertion *ava )
323 {
324         int rc = LDAP_NO_SUCH_ATTRIBUTE;
325         Attribute *a;
326
327         if ( ! access_allowed( op, e,
328                 ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) )
329         {       
330                 return LDAP_INSUFFICIENT_ACCESS;
331         }
332
333         for(a = attrs_find( e->e_attrs, ava->aa_desc );
334                 a != NULL;
335                 a = attrs_find( a->a_next, ava->aa_desc ))
336         {
337                 rc = LDAP_COMPARE_FALSE;
338
339 #ifdef SLAP_NVALUES
340                 if ( value_find_ex( ava->aa_desc,
341                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
342                                 SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
343                         a->a_nvals,
344                         &ava->aa_value ) == 0 )
345 #else
346                 if ( value_find( ava->aa_desc, a->a_vals, &ava->aa_value ) == 0 )
347 #endif
348                 {
349                         rc = LDAP_COMPARE_TRUE;
350                         break;
351                 }
352         }
353
354         return rc;
355 }