]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/compare.c
30314eb9f672435ea5ae9adf69ae8f066def5ad5
[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-2004 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, *err = NULL;
41         struct berval mmatch = { 0, NULL };
42         int candidates = 0, last = 0, i, count = 0, rc;
43         int cres = LDAP_SUCCESS, rres = LDAP_SUCCESS;
44         int *msgid;
45         dncookie dc;
46
47         lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE,
48                         &op->o_req_ndn, NULL );
49         if ( !lc ) {
50                 send_ldap_result( op, rs );
51                 return -1;
52         }
53         
54         if ( !meta_back_dobind( lc, op ) ) {
55                 rs->sr_err = LDAP_OTHER;
56                 send_ldap_result( op, rs );
57                 return -1;
58         }
59
60         msgid = ch_calloc( sizeof( int ), li->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->conns; !META_LAST(lsc); ++i, ++lsc ) {
73                 struct berval mdn = { 0, NULL };
74                 struct berval mapped_attr = op->oq_compare.rs_ava->aa_desc->ad_cname;
75                 struct berval mapped_value = op->oq_compare.rs_ava->aa_value;
76
77                 if ( lsc->candidate != META_CANDIDATE ) {
78                         msgid[ i ] = -1;
79                         continue;
80                 }
81
82                 /*
83                  * Rewrite the compare dn, if needed
84                  */
85                 dc.rwmap = &li->targets[ i ]->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->oq_compare.rs_ava->aa_desc == slap_schema.si_ad_objectClass ) {
100                         ldap_back_map( &li->targets[ i ]->rwmap.rwm_oc,
101                                         &op->oq_compare.rs_ava->aa_value,
102                                         &mapped_value, BACKLDAP_MAP );
103
104                         if ( mapped_value.bv_val == NULL || 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->targets[ i ]->rwmap.rwm_at,
112                                 &op->oq_compare.rs_ava->aa_desc->ad_cname,
113                                 &mapped_attr, BACKLDAP_MAP );
114                         if ( mapped_attr.bv_val == NULL || mapped_attr.bv_val[0] == '\0' ) {
115                                 continue;
116                         }
117                 }
118                 
119                 /*
120                  * the compare op is spawned across the targets and the first
121                  * that returns determines the result; a constraint on unicity
122                  * of the result ought to be enforced
123                  */
124                 msgid[ i ] = ldap_compare( lc->conns[ i ].ld, mdn.bv_val,
125                                 mapped_attr.bv_val, mapped_value.bv_val );
126                 if ( mdn.bv_val != op->o_req_dn.bv_val ) {
127                         free( mdn.bv_val );
128                         mdn.bv_val = NULL;
129                 }
130                 if ( mapped_attr.bv_val != op->oq_compare.rs_ava->aa_desc->ad_cname.bv_val ) {
131                         free( mapped_attr.bv_val );
132                 }
133                 if ( mapped_value.bv_val != op->oq_compare.rs_ava->aa_value.bv_val ) {
134                         free( mapped_value.bv_val );
135                 }
136
137                 if ( msgid[ i ] == -1 ) {
138                         continue;
139                 }
140
141                 ++candidates;
142         }
143
144         /*
145          * wait for replies
146          */
147         for ( rc = 0, count = 0; candidates > 0; ) {
148
149                 /*
150                  * FIXME: should we check for abandon?
151                  */
152                 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
153                         int             lrc;
154                         LDAPMessage     *res = NULL;
155
156                         if ( msgid[ i ] == -1 ) {
157                                 continue;
158                         }
159
160                         lrc = ldap_result( lsc->ld, msgid[ i ],
161                                         0, NULL, &res );
162
163                         if ( lrc == 0 ) {
164                                 /*
165                                  * FIXME: should we yield?
166                                  */
167                                 if ( res ) {
168                                         ldap_msgfree( res );
169                                 }
170                                 continue;
171
172                         } else if ( lrc == LDAP_RES_COMPARE ) {
173                                 if ( count > 0 ) {
174                                         rres = LDAP_OTHER;
175                                         rc = -1;
176                                         goto finish;
177                                 }
178                                 
179                                 rs->sr_err = ldap_result2error( lsc->ld, res, 1 );
180                                 switch ( rs->sr_err ) {
181                                 case LDAP_COMPARE_TRUE:
182                                 case LDAP_COMPARE_FALSE:
183
184                                         /*
185                                          * true or flase, got it;
186                                          * sending to cache ...
187                                          */
188                                         if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
189                                                 ( void )meta_dncache_update_entry( &li->cache, &op->o_req_ndn, i );
190                                         }
191
192                                         count++;
193                                         rc = 0;
194                                         break;
195
196                                 default:
197                                         rres = ldap_back_map_result( rs );
198
199                                         if ( err != NULL ) {
200                                                 free( err );
201                                         }
202                                         ldap_get_option( lsc->ld,
203                                                 LDAP_OPT_ERROR_STRING, &err );
204
205                                         if ( match != NULL ) {
206                                                 free( match );
207                                         }
208                                         ldap_get_option( lsc->ld,
209                                                 LDAP_OPT_MATCHED_DN, &match );
210                                         
211                                         last = i;
212                                         break;
213                                 }
214                                 msgid[ i ] = -1;
215                                 --candidates;
216
217                         } else {
218                                 msgid[ i ] = -1;
219                                 --candidates;
220                                 if ( res ) {
221                                         ldap_msgfree( res );
222                                 }
223                                 break;
224                         }
225                 }
226         }
227
228 finish:;
229
230         /*
231          * Rewrite the matched portion of the search base, if required
232          * 
233          * FIXME: only the last one gets caught!
234          */
235         if ( count == 1 ) {
236                 if ( match != NULL ) {
237                         free( match );
238                         match = NULL;
239                 }
240                 
241                 /*
242                  * the result of the compare is assigned to the res code
243                  * that will be returned
244                  */
245                 rres = cres;
246                 
247                 /*
248                  * At least one compare failed with matched portion,
249                  * and none was successful
250                  */
251         } else if ( match != NULL &&  match[0] != '\0' ) {
252                 struct berval matched;
253
254                 matched.bv_val = match;
255                 matched.bv_len = strlen( match );
256
257                 dc.ctx = "matchedDN";
258                 ldap_back_dn_massage( &dc, &matched, &mmatch );
259         }
260
261         if ( rres != LDAP_SUCCESS ) {
262                 rs->sr_err = rres;
263         }
264         rs->sr_matched = mmatch.bv_val;
265         send_ldap_result( op, rs );
266         rs->sr_matched = NULL;
267
268         if ( match != NULL ) {
269                 if ( mmatch.bv_val != match ) {
270                         free( mmatch.bv_val );
271                 }
272                 free( match );
273         }
274
275         if ( msgid ) {
276                 free( msgid );
277         }
278         
279         return rc;
280 }
281