]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/compare.c
Fix prev commit, return generated passwd
[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-2003 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* ACKNOWLEDGEMENTS:
16  * This work was initially developed by the Howard Chu for inclusion
17  * in OpenLDAP Software and subsequently enhanced by Pierangelo
18  * Masarati.
19  */
20 /* This is an altered version */
21 /*
22  * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
23  *
24  * This work has been developed to fulfill the requirements
25  * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
26  * to the OpenLDAP Foundation in the hope that it may be useful
27  * to the Open Source community, but WITHOUT ANY WARRANTY.
28  *
29  * Permission is granted to anyone to use this software for any purpose
30  * on any computer system, and to alter it and redistribute it, subject
31  * to the following restrictions:
32  *
33  * 1. The author and SysNet s.n.c. are not responsible for the consequences
34  *    of use of this software, no matter how awful, even if they arise from 
35  *    flaws in it.
36  *
37  * 2. The origin of this software must not be misrepresented, either by
38  *    explicit claim or by omission.  Since few users ever read sources,
39  *    credits should appear in the documentation.
40  *
41  * 3. Altered versions must be plainly marked as such, and must not be
42  *    misrepresented as being the original software.  Since few users
43  *    ever read sources, credits should appear in the documentation.
44  *    SysNet s.n.c. cannot be responsible for the consequences of the
45  *    alterations.
46  * 
47  * 4. This notice may not be removed or altered.
48  *
49  *
50  * This software is based on the backend back-ldap, implemented
51  * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
52  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
53  * contributors. The contribution of the original software to the present
54  * implementation is acknowledged in this copyright statement.
55  *
56  * A special acknowledgement goes to Howard for the overall architecture
57  * (and for borrowing large pieces of code), and to Mark, who implemented
58  * from scratch the attribute/objectclass mapping.
59  *
60  * The original copyright statement follows.
61  *
62  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
63  *
64  * Permission is granted to anyone to use this software for any purpose
65  * on any computer system, and to alter it and redistribute it, subject
66  * to the following restrictions:
67  *
68  * 1. The author is not responsible for the consequences of use of this
69  *    software, no matter how awful, even if they arise from flaws in it.
70  *
71  * 2. The origin of this software must not be misrepresented, either by
72  *    explicit claim or by omission.  Since few users ever read sources,
73  *    credits should appear in the documentation.
74  *
75  * 3. Altered versions must be plainly marked as such, and must not be
76  *    misrepresented as being the original software.  Since few users
77  *    ever read sources, credits should appear in the
78  *    documentation.
79  *
80  * 4. This notice may not be removed or altered.
81  *
82  */
83
84 #include "portable.h"
85
86 #include <stdio.h>
87
88 #include <ac/string.h>
89 #include <ac/socket.h>
90
91 #include "slap.h"
92 #include "../back-ldap/back-ldap.h"
93 #include "back-meta.h"
94
95 int
96 meta_back_compare( Operation *op, SlapReply *rs )
97 {
98         struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
99         struct metaconn *lc;
100         struct metasingleconn *lsc;
101         char *match = NULL, *err = NULL;
102         struct berval mmatch = { 0, NULL };
103         int candidates = 0, last = 0, i, count = 0, rc;
104         int cres = LDAP_SUCCESS, rres = LDAP_SUCCESS;
105         int *msgid;
106         dncookie dc;
107
108         lc = meta_back_getconn( op, rs, META_OP_ALLOW_MULTIPLE,
109                         &op->o_req_ndn, NULL );
110         if ( !lc ) {
111                 send_ldap_result( op, rs );
112                 return -1;
113         }
114         
115         if ( !meta_back_dobind( lc, op ) ) {
116                 rs->sr_err = LDAP_OTHER;
117                 send_ldap_result( op, rs );
118                 return -1;
119         }
120
121         msgid = ch_calloc( sizeof( int ), li->ntargets );
122         if ( msgid == NULL ) {
123                 return -1;
124         }
125
126         /*
127          * start an asynchronous compare for each candidate target
128          */
129         dc.conn = op->o_conn;
130         dc.rs = rs;
131         dc.ctx = "compareDn";
132
133         for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
134                 struct berval mdn = { 0, NULL };
135                 struct berval mapped_attr = op->oq_compare.rs_ava->aa_desc->ad_cname;
136                 struct berval mapped_value = op->oq_compare.rs_ava->aa_value;
137
138                 if ( lsc->candidate != META_CANDIDATE ) {
139                         msgid[ i ] = -1;
140                         continue;
141                 }
142
143                 /*
144                  * Rewrite the compare dn, if needed
145                  */
146                 dc.rwmap = &li->targets[ i ]->rwmap;
147
148                 switch ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
149                 case LDAP_UNWILLING_TO_PERFORM:
150                         rc = 1;
151                         goto finish;
152
153                 default:
154                         break;
155                 }
156
157                 /*
158                  * if attr is objectClass, try to remap the value
159                  */
160                 if ( op->oq_compare.rs_ava->aa_desc == slap_schema.si_ad_objectClass ) {
161                         ldap_back_map( &li->targets[ i ]->rwmap.rwm_oc,
162                                         &op->oq_compare.rs_ava->aa_value,
163                                         &mapped_value, BACKLDAP_MAP );
164
165                         if ( mapped_value.bv_val == NULL || mapped_value.bv_val[0] == '\0' ) {
166                                 continue;
167                         }
168                 /*
169                  * else try to remap the attribute
170                  */
171                 } else {
172                         ldap_back_map( &li->targets[ i ]->rwmap.rwm_at,
173                                 &op->oq_compare.rs_ava->aa_desc->ad_cname,
174                                 &mapped_attr, BACKLDAP_MAP );
175                         if ( mapped_attr.bv_val == NULL || mapped_attr.bv_val[0] == '\0' ) {
176                                 continue;
177                         }
178                 }
179                 
180                 /*
181                  * the compare op is spawned across the targets and the first
182                  * that returns determines the result; a constraint on unicity
183                  * of the result ought to be enforced
184                  */
185                 msgid[ i ] = ldap_compare( lc->conns[ i ].ld, mdn.bv_val,
186                                 mapped_attr.bv_val, mapped_value.bv_val );
187                 if ( mdn.bv_val != op->o_req_dn.bv_val ) {
188                         free( mdn.bv_val );
189                         mdn.bv_val = NULL;
190                 }
191                 if ( mapped_attr.bv_val != op->oq_compare.rs_ava->aa_desc->ad_cname.bv_val ) {
192                         free( mapped_attr.bv_val );
193                 }
194                 if ( mapped_value.bv_val != op->oq_compare.rs_ava->aa_value.bv_val ) {
195                         free( mapped_value.bv_val );
196                 }
197
198                 if ( msgid[ i ] == -1 ) {
199                         continue;
200                 }
201
202                 ++candidates;
203         }
204
205         /*
206          * wait for replies
207          */
208         for ( rc = 0, count = 0; candidates > 0; ) {
209
210                 /*
211                  * FIXME: should we check for abandon?
212                  */
213                 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
214                         int             lrc;
215                         LDAPMessage     *res = NULL;
216
217                         if ( msgid[ i ] == -1 ) {
218                                 continue;
219                         }
220
221                         lrc = ldap_result( lsc->ld, msgid[ i ],
222                                         0, NULL, &res );
223
224                         if ( lrc == 0 ) {
225                                 /*
226                                  * FIXME: should we yield?
227                                  */
228                                 if ( res ) {
229                                         ldap_msgfree( res );
230                                 }
231                                 continue;
232
233                         } else if ( lrc == LDAP_RES_COMPARE ) {
234                                 if ( count > 0 ) {
235                                         rres = LDAP_OTHER;
236                                         rc = -1;
237                                         goto finish;
238                                 }
239                                 
240                                 rs->sr_err = ldap_result2error( lsc->ld, res, 1 );
241                                 switch ( rs->sr_err ) {
242                                 case LDAP_COMPARE_TRUE:
243                                 case LDAP_COMPARE_FALSE:
244
245                                         /*
246                                          * true or flase, got it;
247                                          * sending to cache ...
248                                          */
249                                         if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
250                                                 ( void )meta_dncache_update_entry( &li->cache, &op->o_req_ndn, i );
251                                         }
252
253                                         count++;
254                                         rc = 0;
255                                         break;
256
257                                 default:
258                                         rres = ldap_back_map_result( rs );
259
260                                         if ( err != NULL ) {
261                                                 free( err );
262                                         }
263                                         ldap_get_option( lsc->ld,
264                                                 LDAP_OPT_ERROR_STRING, &err );
265
266                                         if ( match != NULL ) {
267                                                 free( match );
268                                         }
269                                         ldap_get_option( lsc->ld,
270                                                 LDAP_OPT_MATCHED_DN, &match );
271                                         
272                                         last = i;
273                                         break;
274                                 }
275                                 msgid[ i ] = -1;
276                                 --candidates;
277
278                         } else {
279                                 msgid[ i ] = -1;
280                                 --candidates;
281                                 if ( res ) {
282                                         ldap_msgfree( res );
283                                 }
284                                 break;
285                         }
286                 }
287         }
288
289 finish:;
290
291         /*
292          * Rewrite the matched portion of the search base, if required
293          * 
294          * FIXME: only the last one gets caught!
295          */
296         if ( count == 1 ) {
297                 if ( match != NULL ) {
298                         free( match );
299                         match = NULL;
300                 }
301                 
302                 /*
303                  * the result of the compare is assigned to the res code
304                  * that will be returned
305                  */
306                 rres = cres;
307                 
308                 /*
309                  * At least one compare failed with matched portion,
310                  * and none was successful
311                  */
312         } else if ( match != NULL &&  match[0] != '\0' ) {
313                 struct berval matched;
314
315                 matched.bv_val = match;
316                 matched.bv_len = strlen( match );
317
318                 dc.ctx = "matchedDn";
319                 ldap_back_dn_massage( &dc, &matched, &mmatch );
320         }
321
322         rs->sr_err = rres;
323         rs->sr_matched = mmatch.bv_val;
324         send_ldap_result( op, rs );
325         rs->sr_matched = NULL;
326
327         if ( match != NULL ) {
328                 if ( mmatch.bv_val != match ) {
329                         free( mmatch.bv_val );
330                 }
331                 free( match );
332         }
333
334         if ( msgid ) {
335                 free( msgid );
336         }
337         
338         return rc;
339 }
340