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