]> git.sur5r.net Git - openldap/blob - servers/slapd/compare.c
bca36de6faacf06c6e609b333fecd34aa80020b9
[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         Connection *conn,
31         Operation *op,
32         Entry *e,
33         AttributeAssertion *ava );
34
35 int
36 do_compare(
37     Connection  *conn,
38     Operation   *op
39 )
40 {
41         Entry *entry = NULL;
42         Entry *fentry = NULL;
43         struct berval dn = { 0, NULL };
44         struct berval pdn = { 0, NULL };
45         struct berval ndn = { 0, NULL };
46         struct berval desc = { 0, NULL };
47         struct berval value = { 0, NULL };
48         AttributeAssertion ava = { NULL, { 0, NULL } };
49         Backend *be;
50         int rc = LDAP_SUCCESS;
51         const char *text = NULL;
52         int manageDSAit;
53
54 #ifdef LDAP_SLAPI
55         Slapi_PBlock *pb = op->o_pb;
56 #endif
57
58         ava.aa_desc = NULL;
59
60 #ifdef NEW_LOGGING
61         LDAP_LOG( OPERATION, ENTRY, "do_compare: conn %d\n", conn->c_connid, 0, 0 );
62 #else
63         Debug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
64 #endif
65         /*
66          * Parse the compare request.  It looks like this:
67          *
68          *      CompareRequest := [APPLICATION 14] SEQUENCE {
69          *              entry   DistinguishedName,
70          *              ava     SEQUENCE {
71          *                      type    AttributeType,
72          *                      value   AttributeValue
73          *              }
74          *      }
75          */
76
77         if ( ber_scanf( op->o_ber, "{m" /*}*/, &dn ) == LBER_ERROR ) {
78 #ifdef NEW_LOGGING
79                 LDAP_LOG( OPERATION, ERR, 
80                         "do_compare: conn %d  ber_scanf failed\n", conn->c_connid, 0, 0 );
81 #else
82                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
83 #endif
84                 send_ldap_disconnect( conn, op,
85                         LDAP_PROTOCOL_ERROR, "decoding error" );
86                 return SLAPD_DISCONNECT;
87         }
88
89         if ( ber_scanf( op->o_ber, "{mm}", &desc, &value ) == LBER_ERROR ) {
90 #ifdef NEW_LOGGING
91                 LDAP_LOG( OPERATION, ERR, 
92                         "do_compare: conn %d  get ava failed\n", conn->c_connid, 0, 0 );
93 #else
94                 Debug( LDAP_DEBUG_ANY, "do_compare: get ava failed\n", 0, 0, 0 );
95 #endif
96                 send_ldap_disconnect( conn, op,
97                         LDAP_PROTOCOL_ERROR, "decoding error" );
98                 rc = SLAPD_DISCONNECT;
99                 goto cleanup;
100         }
101
102         if ( ber_scanf( op->o_ber, /*{*/ "}" ) == LBER_ERROR ) {
103 #ifdef NEW_LOGGING
104                 LDAP_LOG( OPERATION, ERR, 
105                         "do_compare: conn %d  ber_scanf failed\n", conn->c_connid, 0, 0 );
106 #else
107                 Debug( LDAP_DEBUG_ANY, "ber_scanf failed\n", 0, 0, 0 );
108 #endif
109                 send_ldap_disconnect( conn, op,
110                         LDAP_PROTOCOL_ERROR, "decoding error" );
111                 rc = SLAPD_DISCONNECT;
112                 goto cleanup;
113         }
114
115         if( ( rc = get_ctrls( conn, op, 1 )) != LDAP_SUCCESS ) {
116 #ifdef NEW_LOGGING
117                 LDAP_LOG( OPERATION, INFO, 
118                         "do_compare: conn %d  get_ctrls failed\n", conn->c_connid, 0, 0 );
119 #else
120                 Debug( LDAP_DEBUG_ANY, "do_compare: get_ctrls failed\n", 0, 0, 0 );
121 #endif
122                 goto cleanup;
123         } 
124
125         rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn );
126         if( rc != LDAP_SUCCESS ) {
127 #ifdef NEW_LOGGING
128                 LDAP_LOG( OPERATION, INFO, 
129                         "do_compare: conn %d  invalid dn (%s)\n",
130                         conn->c_connid, dn.bv_val, 0 );
131 #else
132                 Debug( LDAP_DEBUG_ANY,
133                         "do_compare: invalid dn (%s)\n", dn.bv_val, 0, 0 );
134 #endif
135                 send_ldap_result( conn, op, rc = LDAP_INVALID_DN_SYNTAX, NULL,
136                     "invalid DN", NULL, NULL );
137                 goto cleanup;
138         }
139
140         rc = slap_bv2ad( &desc, &ava.aa_desc, &text );
141         if( rc != LDAP_SUCCESS ) {
142                 send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
143                 goto cleanup;
144         }
145
146 #ifdef SLAP_NVALUES
147         rc = asserted_value_validate_normalize( ava.aa_desc,
148                 ava.aa_desc->ad_type->sat_equality,
149                 SLAP_MR_EQUALITY|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
150                 &value, &ava.aa_value, &text );
151 #else
152         rc = value_validate_normalize( ava.aa_desc, SLAP_MR_EQUALITY,
153                 &value, &ava.aa_value, &text );
154 #endif
155         if( rc != LDAP_SUCCESS ) {
156                 send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
157                 goto cleanup;
158         }
159
160         if( strcasecmp( ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) {
161 #ifdef NEW_LOGGING
162                 LDAP_LOG( OPERATION, ARGS, 
163                         "do_compare: dn (%s) attr(%s) value (%s)\n",
164                         pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
165 #else
166                 Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
167                         pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
168 #endif
169
170                 Statslog( LDAP_DEBUG_STATS,
171                         "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n",
172                         op->o_connid, op->o_opid, pdn.bv_val,
173                         ava.aa_desc->ad_cname.bv_val, 0 );
174
175                 rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ;
176                 if( rc != LDAP_SUCCESS ) {
177                         send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
178                         goto cleanup;
179                 }
180
181                 rc = root_dse_info( conn, &entry, &text );
182                 if( rc != LDAP_SUCCESS ) {
183                         send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
184                         goto cleanup;
185                 }
186
187                 fentry = entry;
188
189         } else if ( bvmatch( &ndn, &global_schemandn ) ) {
190 #ifdef NEW_LOGGING
191                 LDAP_LOG( OPERATION, ARGS, 
192                         "do_compare: dn (%s) attr(%s) value (%s)\n",
193                         pdn.bv_val, ava.aa_desc->ad_cname.bv_val,
194                         ava.aa_value.bv_val );
195 #else
196                 Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
197                         pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
198 #endif
199
200                 Statslog( LDAP_DEBUG_STATS,
201                         "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n",
202                         op->o_connid, op->o_opid, pdn.bv_val,
203                         ava.aa_desc->ad_cname.bv_val, 0 );
204
205                 rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ;
206                 if( rc != LDAP_SUCCESS ) {
207                         send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
208                         rc = 0;
209                         goto cleanup;
210                 }
211
212                 rc = schema_info( &entry, &text );
213                 if( rc != LDAP_SUCCESS ) {
214                         send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
215                         rc = 0;
216                         goto cleanup;
217                 }
218                 fentry = entry;
219         }
220
221         if( entry ) {
222                 rc = compare_entry( conn, op, entry, &ava );
223                 if( fentry) entry_free( fentry );
224
225                 send_ldap_result( conn, op, rc, NULL, text, NULL, NULL );
226
227                 if( rc == LDAP_COMPARE_TRUE || rc == LDAP_COMPARE_FALSE ) {
228                         rc = 0;
229                 }
230
231                 goto cleanup;
232         }
233
234         manageDSAit = get_manageDSAit( op );
235
236         /*
237          * We could be serving multiple database backends.  Select the
238          * appropriate one, or send a referral to our "referral server"
239          * if we don't hold it.
240          */
241         if ( (be = select_backend( &ndn, manageDSAit, 0 )) == NULL ) {
242                 BerVarray ref = referral_rewrite( default_referral,
243                         NULL, &pdn, LDAP_SCOPE_DEFAULT );
244
245                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
246                         NULL, NULL, ref ? ref : default_referral, NULL );
247
248                 ber_bvarray_free( ref );
249                 rc = 0;
250                 goto cleanup;
251         }
252
253         /* check restrictions */
254         rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
255         if( rc != LDAP_SUCCESS ) {
256                 send_ldap_result( conn, op, rc,
257                         NULL, text, NULL, NULL );
258                 goto cleanup;
259         }
260
261         /* check for referrals */
262         rc = backend_check_referrals( be, conn, op, &pdn, &ndn );
263         if ( rc != LDAP_SUCCESS ) {
264                 goto cleanup;
265         }
266
267 #ifdef NEW_LOGGING
268         LDAP_LOG( OPERATION, ARGS, 
269                 "do_compare: dn (%s) attr(%s) value (%s)\n",
270                 pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
271 #else
272         Debug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s) value (%s)\n",
273             pdn.bv_val, ava.aa_desc->ad_cname.bv_val, ava.aa_value.bv_val );
274 #endif
275
276         Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu CMP dn=\"%s\" attr=\"%s\"\n",
277             op->o_connid, op->o_opid, pdn.bv_val,
278                 ava.aa_desc->ad_cname.bv_val, 0 );
279
280 #if defined( LDAP_SLAPI )
281         slapi_x_backend_set_pb( pb, be );
282         slapi_x_connection_set_pb( pb, conn );
283         slapi_x_operation_set_pb( pb, op );
284         slapi_pblock_set( pb, SLAPI_COMPARE_TARGET, (void *)dn.bv_val );
285         slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)manageDSAit );
286         slapi_pblock_set( pb, SLAPI_COMPARE_TYPE, (void *)desc.bv_val );
287         slapi_pblock_set( pb, SLAPI_COMPARE_VALUE, (void *)&value );
288
289         rc = doPluginFNs( be, SLAPI_PLUGIN_PRE_COMPARE_FN, pb );
290         if ( rc != 0 ) {
291                 /*
292                  * A preoperation plugin failure will abort the
293                  * entire operation.
294                  */
295 #ifdef NEW_LOGGING
296                 LDAP_LOG( OPERATION, INFO, "do_compare: compare preoperation plugin "
297                                 "failed\n", 0, 0, 0);
298 #else
299                 Debug(LDAP_DEBUG_TRACE, "do_compare: compare preoperation plugin "
300                                 "failed.\n", 0, 0, 0);
301 #endif
302                 if ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rc ) != 0)
303                         rc = LDAP_OTHER;
304                 goto cleanup;
305         }
306 #endif /* defined( LDAP_SLAPI ) */
307
308         if ( be->be_compare ) {
309                 (*be->be_compare)( be, conn, op, &pdn, &ndn, &ava );
310         } else {
311                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
312                         NULL, "operation not supported within namingContext",
313                         NULL, NULL );
314         }
315
316 #if defined( LDAP_SLAPI )
317         if ( doPluginFNs( be, SLAPI_PLUGIN_POST_COMPARE_FN, pb ) != 0 ) {
318 #ifdef NEW_LOGGING
319                 LDAP_LOG( OPERATION, INFO, "do_compare: compare postoperation plugins "
320                                 "failed\n", 0, 0, 0 );
321 #else
322                 Debug(LDAP_DEBUG_TRACE, "do_compare: compare postoperation plugins "
323                                 "failed.\n", 0, 0, 0);
324 #endif
325         }
326 #endif /* defined( LDAP_SLAPI ) */
327
328 cleanup:
329         free( pdn.bv_val );
330         free( ndn.bv_val );
331         if ( ava.aa_value.bv_val ) free( ava.aa_value.bv_val );
332
333         return rc;
334 }
335
336 static int compare_entry(
337         Connection *conn,
338         Operation *op,
339         Entry *e,
340         AttributeAssertion *ava )
341 {
342         int rc = LDAP_NO_SUCH_ATTRIBUTE;
343         Attribute *a;
344
345         if ( ! access_allowed( NULL, conn, op, e,
346                 ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) )
347         {       
348                 return LDAP_INSUFFICIENT_ACCESS;
349         }
350
351         for(a = attrs_find( e->e_attrs, ava->aa_desc );
352                 a != NULL;
353                 a = attrs_find( a->a_next, ava->aa_desc ))
354         {
355                 rc = LDAP_COMPARE_FALSE;
356
357 #ifdef SLAP_NVALUES
358                 if ( value_find_ex( ava->aa_desc,
359                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
360                         a->a_nvals ? a->a_nvals : a->a_vals,
361                         &ava->aa_value ) == 0 )
362 #else
363                 if ( value_find( ava->aa_desc, a->a_vals, &ava->aa_value ) == 0 )
364 #endif
365                 {
366                         rc = LDAP_COMPARE_TRUE;
367                         break;
368                 }
369         }
370
371         return rc;
372 }