]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/compare.c
c9fc9fb137b7dac7c3eb0e38012a1a62f82fdda5
[openldap] / servers / slapd / back-meta / compare.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/string.h>
28 #include <ac/socket.h>
29
30 #include "slap.h"
31 #include "../back-ldap/back-ldap.h"
32 #include "back-meta.h"
33
34 int
35 meta_back_compare( Operation *op, SlapReply *rs )
36 {
37         struct metainfo         *li = ( struct metainfo * )op->o_bd->be_private;
38         struct metaconn         *lc;
39         struct metasingleconn   *lsc;
40         char                    *match = NULL,
41                                 *err = NULL;
42         struct berval           mmatch = BER_BVNULL;
43         int                     ncandidates = 0,
44                                 last = 0,
45                                 i,
46                                 count = 0,
47                                 rc,
48                                 cres = LDAP_SUCCESS,
49                                 rres = LDAP_SUCCESS,
50                                 *msgid;
51         dncookie                dc;
52
53         char                    *candidates = meta_back_candidates_get( op );
54
55         lc = meta_back_getconn( op, rs, NULL, LDAP_BACK_SENDERR );
56         if ( !lc || !meta_back_dobind( lc, op, LDAP_BACK_SENDERR ) ) {
57                 return rs->sr_err;
58         }
59         
60         msgid = ch_calloc( sizeof( int ), li->mi_ntargets );
61         if ( msgid == NULL ) {
62                 return -1;
63         }
64
65         /*
66          * start an asynchronous compare for each candidate target
67          */
68         dc.conn = op->o_conn;
69         dc.rs = rs;
70         dc.ctx = "compareDN";
71
72         for ( i = 0, lsc = lc->mc_conns; !META_LAST( lsc ); ++i, ++lsc ) {
73                 struct berval mdn = BER_BVNULL;
74                 struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
75                 struct berval mapped_value = op->orc_ava->aa_value;
76
77                 if ( candidates[ i ] != META_CANDIDATE ) {
78                         msgid[ i ] = -1;
79                         continue;
80                 }
81
82                 /*
83                  * Rewrite the compare dn, if needed
84                  */
85                 dc.rwmap = &li->mi_targets[ i ]->mt_rwmap;
86
87                 switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
88                 case LDAP_UNWILLING_TO_PERFORM:
89                         rc = 1;
90                         goto finish;
91
92                 default:
93                         break;
94                 }
95
96                 /*
97                  * if attr is objectClass, try to remap the value
98                  */
99                 if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) {
100                         ldap_back_map( &li->mi_targets[ i ]->mt_rwmap.rwm_oc,
101                                         &op->orc_ava->aa_value,
102                                         &mapped_value, BACKLDAP_MAP );
103
104                         if ( BER_BVISNULL( &mapped_value ) || mapped_value.bv_val[0] == '\0' ) {
105                                 continue;
106                         }
107                 /*
108                  * else try to remap the attribute
109                  */
110                 } else {
111                         ldap_back_map( &li->mi_targets[ i ]->mt_rwmap.rwm_at,
112                                 &op->orc_ava->aa_desc->ad_cname,
113                                 &mapped_attr, BACKLDAP_MAP );
114                         if ( BER_BVISNULL( &mapped_attr ) || mapped_attr.bv_val[0] == '\0' ) {
115                                 continue;
116                         }
117
118                         if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
119                         {
120                                 dc.ctx = "compareAttrDN";
121
122                                 switch ( ldap_back_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) )
123                                 {
124                                 case LDAP_UNWILLING_TO_PERFORM:
125                                         rc = 1;
126                                         goto finish;
127
128                                 default:
129                                         break;
130                                 }
131                         }
132                 }
133                 
134                 /*
135                  * the compare op is spawned across the targets and the first
136                  * that returns determines the result; a constraint on unicity
137                  * of the result ought to be enforced
138                  */
139                  rc = ldap_compare_ext( lc->mc_conns[ i ].msc_ld, mdn.bv_val,
140                                 mapped_attr.bv_val, &mapped_value,
141                                 op->o_ctrls, NULL, &msgid[ i ] );
142
143                 if ( mdn.bv_val != op->o_req_dn.bv_val ) {
144                         free( mdn.bv_val );
145                         BER_BVZERO( &mdn );
146                 }
147
148                 if ( mapped_attr.bv_val != op->orc_ava->aa_desc->ad_cname.bv_val ) {
149                         free( mapped_attr.bv_val );
150                         BER_BVZERO( &mapped_attr );
151                 }
152
153                 if ( mapped_value.bv_val != op->orc_ava->aa_value.bv_val ) {
154                         free( mapped_value.bv_val );
155                         BER_BVZERO( &mapped_value );
156                 }
157
158                 if ( rc != LDAP_SUCCESS ) {
159                         /* FIXME: what should we do with the error? */
160                         continue;
161                 }
162
163                 ++ncandidates;
164         }
165
166         /*
167          * wait for replies
168          */
169         for ( rc = 0, count = 0; ncandidates > 0; ) {
170
171                 /*
172                  * FIXME: should we check for abandon?
173                  */
174                 for ( i = 0, lsc = lc->mc_conns; !META_LAST( lsc ); lsc++, i++ ) {
175                         int             lrc;
176                         LDAPMessage     *res = NULL;
177
178                         if ( msgid[ i ] == -1 ) {
179                                 continue;
180                         }
181
182                         lrc = ldap_result( lsc->msc_ld, msgid[ i ],
183                                         0, NULL, &res );
184
185                         if ( lrc == 0 ) {
186                                 /*
187                                  * FIXME: should we yield?
188                                  */
189                                 if ( res ) {
190                                         ldap_msgfree( res );
191                                 }
192                                 continue;
193
194                         } else if ( lrc == LDAP_RES_COMPARE ) {
195                                 if ( count > 0 ) {
196                                         rres = LDAP_OTHER;
197                                         rc = -1;
198                                         goto finish;
199                                 }
200
201                                 rc = ldap_parse_result( lsc->msc_ld, res,
202                                                 &rs->sr_err,
203                                                 NULL, NULL, NULL, NULL, 1 );
204                                 if ( rc != LDAP_SUCCESS ) {
205                                         rres = rc;
206                                         rc = -1;
207                                         goto finish;
208                                 }
209                                 
210                                 switch ( rs->sr_err ) {
211                                 case LDAP_COMPARE_TRUE:
212                                 case LDAP_COMPARE_FALSE:
213
214                                         /*
215                                          * true or flase, got it;
216                                          * sending to cache ...
217                                          */
218                                         if ( li->mi_cache.ttl != META_DNCACHE_DISABLED ) {
219                                                 ( void )meta_dncache_update_entry( &li->mi_cache, &op->o_req_ndn, i );
220                                         }
221
222                                         count++;
223                                         rc = 0;
224                                         break;
225
226                                 default:
227                                         rres = slap_map_api2result( rs );
228
229                                         if ( err != NULL ) {
230                                                 free( err );
231                                         }
232                                         ldap_get_option( lsc->msc_ld,
233                                                 LDAP_OPT_ERROR_STRING, &err );
234
235                                         if ( match != NULL ) {
236                                                 free( match );
237                                         }
238                                         ldap_get_option( lsc->msc_ld,
239                                                 LDAP_OPT_MATCHED_DN, &match );
240                                         
241                                         last = i;
242                                         break;
243                                 }
244                                 msgid[ i ] = -1;
245                                 --ncandidates;
246
247                         } else {
248                                 msgid[ i ] = -1;
249                                 --ncandidates;
250                                 if ( res ) {
251                                         ldap_msgfree( res );
252                                 }
253                                 break;
254                         }
255                 }
256         }
257
258 finish:;
259
260         /*
261          * Rewrite the matched portion of the search base, if required
262          * 
263          * FIXME: only the last one gets caught!
264          */
265         if ( count == 1 ) {
266                 if ( match != NULL ) {
267                         free( match );
268                         match = NULL;
269                 }
270                 
271                 /*
272                  * the result of the compare is assigned to the res code
273                  * that will be returned
274                  */
275                 rres = cres;
276                 
277                 /*
278                  * At least one compare failed with matched portion,
279                  * and none was successful
280                  */
281         } else if ( match != NULL &&  match[0] != '\0' ) {
282                 struct berval matched;
283
284                 ber_str2bv( match, 0, 0, &matched );
285
286                 dc.ctx = "matchedDN";
287                 ldap_back_dn_massage( &dc, &matched, &mmatch );
288         }
289
290         if ( rres != LDAP_SUCCESS ) {
291                 rs->sr_err = rres;
292         }
293         rs->sr_matched = mmatch.bv_val;
294         send_ldap_result( op, rs );
295         rs->sr_matched = NULL;
296
297         if ( match != NULL ) {
298                 if ( mmatch.bv_val != match ) {
299                         free( mmatch.bv_val );
300                 }
301                 free( match );
302         }
303
304         if ( msgid ) {
305                 free( msgid );
306         }
307         
308         return rc;
309 }
310