]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/compare.c
major namespace cleanup & minor fixes
[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                     candidates = 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         lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE,
54                         &op->o_req_ndn, NULL );
55         if ( !lc ) {
56                 send_ldap_result( op, rs );
57                 return -1;
58         }
59         
60         if ( !meta_back_dobind( lc, op ) ) {
61                 rs->sr_err = LDAP_OTHER;
62                 send_ldap_result( op, rs );
63                 return -1;
64         }
65
66         msgid = ch_calloc( sizeof( int ), li->ntargets );
67         if ( msgid == NULL ) {
68                 return -1;
69         }
70
71         /*
72          * start an asynchronous compare for each candidate target
73          */
74         dc.conn = op->o_conn;
75         dc.rs = rs;
76         dc.ctx = "compareDN";
77
78         for ( i = 0, lsc = lc->mc_conns; !META_LAST( lsc ); ++i, ++lsc ) {
79                 struct berval mdn = BER_BVNULL;
80                 struct berval mapped_attr = op->orc_ava->aa_desc->ad_cname;
81                 struct berval mapped_value = op->orc_ava->aa_value;
82
83                 if ( lsc->msc_candidate != META_CANDIDATE ) {
84                         msgid[ i ] = -1;
85                         continue;
86                 }
87
88                 /*
89                  * Rewrite the compare dn, if needed
90                  */
91                 dc.rwmap = &li->targets[ i ]->mt_rwmap;
92
93                 switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
94                 case LDAP_UNWILLING_TO_PERFORM:
95                         rc = 1;
96                         goto finish;
97
98                 default:
99                         break;
100                 }
101
102                 /*
103                  * if attr is objectClass, try to remap the value
104                  */
105                 if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass ) {
106                         ldap_back_map( &li->targets[ i ]->mt_rwmap.rwm_oc,
107                                         &op->orc_ava->aa_value,
108                                         &mapped_value, BACKLDAP_MAP );
109
110                         if ( mapped_value.bv_val == NULL || mapped_value.bv_val[0] == '\0' ) {
111                                 continue;
112                         }
113                 /*
114                  * else try to remap the attribute
115                  */
116                 } else {
117                         ldap_back_map( &li->targets[ i ]->mt_rwmap.rwm_at,
118                                 &op->orc_ava->aa_desc->ad_cname,
119                                 &mapped_attr, BACKLDAP_MAP );
120                         if ( mapped_attr.bv_val == NULL || mapped_attr.bv_val[0] == '\0' ) {
121                                 continue;
122                         }
123
124                         if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName )
125                         {
126                                 dc.ctx = "compareAttrDN";
127
128                                 switch ( ldap_back_dn_massage( &dc, &op->orc_ava->aa_value, &mapped_value ) )
129                                 {
130                                 case LDAP_UNWILLING_TO_PERFORM:
131                                         rc = 1;
132                                         goto finish;
133
134                                 default:
135                                         break;
136                                 }
137                         }
138                 }
139                 
140                 /*
141                  * the compare op is spawned across the targets and the first
142                  * that returns determines the result; a constraint on unicity
143                  * of the result ought to be enforced
144                  */
145                  rc = ldap_compare_ext( lc->mc_conns[ i ].msc_ld, mdn.bv_val,
146                                 mapped_attr.bv_val, &mapped_value,
147                                 NULL, NULL, &msgid[ i ] );
148
149                 if ( mdn.bv_val != op->o_req_dn.bv_val ) {
150                         free( mdn.bv_val );
151                         BER_BVZERO( &mdn );
152                 }
153
154                 if ( mapped_attr.bv_val != op->orc_ava->aa_desc->ad_cname.bv_val ) {
155                         free( mapped_attr.bv_val );
156                         BER_BVZERO( &mapped_attr );
157                 }
158
159                 if ( mapped_value.bv_val != op->orc_ava->aa_value.bv_val ) {
160                         free( mapped_value.bv_val );
161                         BER_BVZERO( &mapped_value );
162                 }
163
164                 if ( rc != LDAP_SUCCESS ) {
165                         /* FIXME: what should we do with the error? */
166                         continue;
167                 }
168
169                 ++candidates;
170         }
171
172         /*
173          * wait for replies
174          */
175         for ( rc = 0, count = 0; candidates > 0; ) {
176
177                 /*
178                  * FIXME: should we check for abandon?
179                  */
180                 for ( i = 0, lsc = lc->mc_conns; !META_LAST( lsc ); lsc++, i++ ) {
181                         int             lrc;
182                         LDAPMessage     *res = NULL;
183
184                         if ( msgid[ i ] == -1 ) {
185                                 continue;
186                         }
187
188                         lrc = ldap_result( lsc->msc_ld, msgid[ i ],
189                                         0, NULL, &res );
190
191                         if ( lrc == 0 ) {
192                                 /*
193                                  * FIXME: should we yield?
194                                  */
195                                 if ( res ) {
196                                         ldap_msgfree( res );
197                                 }
198                                 continue;
199
200                         } else if ( lrc == LDAP_RES_COMPARE ) {
201                                 if ( count > 0 ) {
202                                         rres = LDAP_OTHER;
203                                         rc = -1;
204                                         goto finish;
205                                 }
206
207                                 rc = ldap_parse_result( lsc->msc_ld, res,
208                                                 &rs->sr_err,
209                                                 NULL, NULL, NULL, NULL, 1 );
210                                 if ( rc != LDAP_SUCCESS ) {
211                                         rres = rc;
212                                         rc = -1;
213                                         goto finish;
214                                 }
215                                 
216                                 switch ( rs->sr_err ) {
217                                 case LDAP_COMPARE_TRUE:
218                                 case LDAP_COMPARE_FALSE:
219
220                                         /*
221                                          * true or flase, got it;
222                                          * sending to cache ...
223                                          */
224                                         if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
225                                                 ( void )meta_dncache_update_entry( &li->cache, &op->o_req_ndn, i );
226                                         }
227
228                                         count++;
229                                         rc = 0;
230                                         break;
231
232                                 default:
233                                         rres = slap_map_api2result( rs );
234
235                                         if ( err != NULL ) {
236                                                 free( err );
237                                         }
238                                         ldap_get_option( lsc->msc_ld,
239                                                 LDAP_OPT_ERROR_STRING, &err );
240
241                                         if ( match != NULL ) {
242                                                 free( match );
243                                         }
244                                         ldap_get_option( lsc->msc_ld,
245                                                 LDAP_OPT_MATCHED_DN, &match );
246                                         
247                                         last = i;
248                                         break;
249                                 }
250                                 msgid[ i ] = -1;
251                                 --candidates;
252
253                         } else {
254                                 msgid[ i ] = -1;
255                                 --candidates;
256                                 if ( res ) {
257                                         ldap_msgfree( res );
258                                 }
259                                 break;
260                         }
261                 }
262         }
263
264 finish:;
265
266         /*
267          * Rewrite the matched portion of the search base, if required
268          * 
269          * FIXME: only the last one gets caught!
270          */
271         if ( count == 1 ) {
272                 if ( match != NULL ) {
273                         free( match );
274                         match = NULL;
275                 }
276                 
277                 /*
278                  * the result of the compare is assigned to the res code
279                  * that will be returned
280                  */
281                 rres = cres;
282                 
283                 /*
284                  * At least one compare failed with matched portion,
285                  * and none was successful
286                  */
287         } else if ( match != NULL &&  match[0] != '\0' ) {
288                 struct berval matched;
289
290                 matched.bv_val = match;
291                 matched.bv_len = strlen( match );
292
293                 dc.ctx = "matchedDN";
294                 ldap_back_dn_massage( &dc, &matched, &mmatch );
295         }
296
297         if ( rres != LDAP_SUCCESS ) {
298                 rs->sr_err = rres;
299         }
300         rs->sr_matched = mmatch.bv_val;
301         send_ldap_result( op, rs );
302         rs->sr_matched = NULL;
303
304         if ( match != NULL ) {
305                 if ( mmatch.bv_val != match ) {
306                         free( mmatch.bv_val );
307                 }
308                 free( match );
309         }
310
311         if ( msgid ) {
312                 free( msgid );
313         }
314         
315         return rc;
316 }
317