~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/back-meta/search.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $OpenLDAP: pkg/ldap/servers/slapd/back-meta/search.c,v 1.146.2.11 2008/04/21 17:03:23 quanah Exp $ */
 
2
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
3
 *
 
4
 * Copyright 1999-2008 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/socket.h>
 
28
#include <ac/string.h>
 
29
#include <ac/time.h>
 
30
 
 
31
#include "lutil.h"
 
32
#include "slap.h"
 
33
#include "../back-ldap/back-ldap.h"
 
34
#include "back-meta.h"
 
35
#undef ldap_debug       /* silence a warning in ldap-int.h */
 
36
#include "ldap_log.h"
 
37
#include "../../../libraries/libldap/ldap-int.h"
 
38
 
 
39
/* IGNORE means that target does not (no longer) participate
 
40
 * in the search;
 
41
 * NOTREADY means the search on that target has not been initialized yet
 
42
 */
 
43
#define META_MSGID_IGNORE       (-1)
 
44
#define META_MSGID_NEED_BIND    (-2)
 
45
#define META_MSGID_CONNECTING   (-3)
 
46
 
 
47
static int
 
48
meta_send_entry(
 
49
        Operation       *op,
 
50
        SlapReply       *rs,
 
51
        metaconn_t      *mc,
 
52
        int             i,
 
53
        LDAPMessage     *e );
 
54
 
 
55
typedef enum meta_search_candidate_t {
 
56
        META_SEARCH_UNDEFINED = -2,
 
57
        META_SEARCH_ERR = -1,
 
58
        META_SEARCH_NOT_CANDIDATE,
 
59
        META_SEARCH_CANDIDATE,
 
60
        META_SEARCH_BINDING,
 
61
        META_SEARCH_NEED_BIND,
 
62
        META_SEARCH_CONNECTING
 
63
} meta_search_candidate_t;
 
64
 
 
65
/*
 
66
 * meta_search_dobind_init()
 
67
 *
 
68
 * initiates bind for a candidate target of a search.
 
69
 */
 
70
static meta_search_candidate_t
 
71
meta_search_dobind_init(
 
72
        Operation               *op,
 
73
        SlapReply               *rs,
 
74
        metaconn_t              **mcp,
 
75
        int                     candidate,
 
76
        SlapReply               *candidates )
 
77
{
 
78
        metaconn_t              *mc = *mcp;
 
79
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
 
80
        metatarget_t            *mt = mi->mi_targets[ candidate ];
 
81
        metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
 
82
 
 
83
        struct berval           binddn = msc->msc_bound_ndn,
 
84
                                cred = msc->msc_cred;
 
85
        int                     method;
 
86
 
 
87
        int                     rc;
 
88
 
 
89
        meta_search_candidate_t retcode;
 
90
 
 
91
        Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
 
92
                op->o_log_prefix, candidate, 0 );
 
93
 
 
94
        /*
 
95
         * all the targets are already bound as pseudoroot
 
96
         */
 
97
        if ( mc->mc_authz_target == META_BOUND_ALL ) {
 
98
                return META_SEARCH_CANDIDATE;
 
99
        }
 
100
 
 
101
        retcode = META_SEARCH_BINDING;
 
102
        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
103
        if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
 
104
                /* already bound (or anonymous) */
 
105
 
 
106
#ifdef DEBUG_205
 
107
                char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
 
108
                int     bound = 0;
 
109
 
 
110
                if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
 
111
                        bound = 1;
 
112
                }
 
113
 
 
114
                snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
 
115
                        (void *)mc, (void *)msc->msc_ld,
 
116
                        bound ? " bound" : " anonymous",
 
117
                        bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
 
118
                Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
 
119
                        op->o_log_prefix, candidate, buf );
 
120
#endif /* DEBUG_205 */
 
121
 
 
122
                retcode = META_SEARCH_CANDIDATE;
 
123
 
 
124
        } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
 
125
                /* another thread is binding the target for this conn; wait */
 
126
 
 
127
#ifdef DEBUG_205
 
128
                char    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
 
129
 
 
130
                snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
 
131
                        (void *)mc, (void *)msc->msc_ld );
 
132
                Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
 
133
                        op->o_log_prefix, candidate, buf );
 
134
#endif /* DEBUG_205 */
 
135
 
 
136
                candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
 
137
                retcode = META_SEARCH_NEED_BIND;
 
138
 
 
139
        } else {
 
140
                /* we'll need to bind the target for this conn */
 
141
 
 
142
#ifdef DEBUG_205
 
143
                char buf[ SLAP_TEXT_BUFLEN ];
 
144
 
 
145
                snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
 
146
                        (void *)mc, (void *)msc->msc_ld );
 
147
                Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
 
148
                        op->o_log_prefix, candidate, buf );
 
149
#endif /* DEBUG_205 */
 
150
 
 
151
                if ( msc->msc_ld == NULL ) {
 
152
                        /* for some reason (e.g. because formerly in "binding"
 
153
                         * state, with eventual connection expiration or invalidation)
 
154
                         * it was not initialized as expected */
 
155
 
 
156
                        Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
 
157
                                op->o_log_prefix, candidate, (void *)mc );
 
158
 
 
159
                        rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
 
160
                                LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
 
161
                        switch ( rc ) {
 
162
                        case LDAP_SUCCESS:
 
163
                                assert( msc->msc_ld != NULL );
 
164
                                break;
 
165
 
 
166
                        case LDAP_SERVER_DOWN:
 
167
                        case LDAP_UNAVAILABLE:
 
168
                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
169
                                goto down;
 
170
        
 
171
                        default:
 
172
                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
173
                                goto other;
 
174
                        }
 
175
                }
 
176
 
 
177
                LDAP_BACK_CONN_BINDING_SET( msc );
 
178
        }
 
179
 
 
180
        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
181
 
 
182
        if ( retcode != META_SEARCH_BINDING ) {
 
183
                return retcode;
 
184
        }
 
185
 
 
186
        /* NOTE: this obsoletes pseudorootdn */
 
187
        if ( op->o_conn != NULL &&
 
188
                !op->o_do_not_cache &&
 
189
                ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
 
190
                        BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
 
191
                        ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
 
192
        {
 
193
                rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
 
194
                if ( rc != LDAP_SUCCESS ) {
 
195
                        goto down;
 
196
                }
 
197
 
 
198
                /* NOTE: we copy things here, even if bind didn't succeed yet,
 
199
                 * because the connection is not shared until bind is over */
 
200
                if ( !BER_BVISNULL( &binddn ) ) {
 
201
                        ber_bvreplace( &msc->msc_bound_ndn, &binddn );
 
202
                        if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) {
 
203
                                if ( !BER_BVISNULL( &msc->msc_cred ) ) {
 
204
                                        memset( msc->msc_cred.bv_val, 0,
 
205
                                                msc->msc_cred.bv_len );
 
206
                                }
 
207
                                ber_bvreplace( &msc->msc_cred, &cred );
 
208
                        }
 
209
                }
 
210
 
 
211
                if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
 
212
                        /* apparently, idassert was configured with SASL bind,
 
213
                         * so bind occurred inside meta_back_proxy_authz_cred() */
 
214
                        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
215
                        LDAP_BACK_CONN_BINDING_CLEAR( msc );
 
216
                        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
217
                        return META_SEARCH_CANDIDATE;
 
218
                }
 
219
 
 
220
                /* paranoid */
 
221
                switch ( method ) {
 
222
                case LDAP_AUTH_NONE:
 
223
                case LDAP_AUTH_SIMPLE:
 
224
                        /* do a simple bind with binddn, cred */
 
225
                        break;
 
226
 
 
227
                default:
 
228
                        assert( 0 );
 
229
                        break;
 
230
                }
 
231
        }
 
232
 
 
233
        assert( msc->msc_ld != NULL );
 
234
 
 
235
        /* connect must be async only the first time... */
 
236
        ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );
 
237
 
 
238
retry:;
 
239
        rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
 
240
                        NULL, NULL, &candidates[ candidate ].sr_msgid );
 
241
 
 
242
#ifdef DEBUG_205
 
243
        {
 
244
                char buf[ SLAP_TEXT_BUFLEN ];
 
245
 
 
246
                snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
 
247
                        candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
 
248
                Debug( LDAP_DEBUG_ANY, "### %s %s\n",
 
249
                        op->o_log_prefix, buf, 0 );
 
250
        }
 
251
#endif /* DEBUG_205 */
 
252
 
 
253
        switch ( rc ) {
 
254
        case LDAP_SUCCESS:
 
255
                assert( candidates[ candidate ].sr_msgid >= 0 );
 
256
                META_BINDING_SET( &candidates[ candidate ] );
 
257
                return META_SEARCH_BINDING;
 
258
 
 
259
        case LDAP_X_CONNECTING:
 
260
                /* must retry, same conn */
 
261
                candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
 
262
                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
263
                LDAP_BACK_CONN_BINDING_CLEAR( msc );
 
264
                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
265
                return META_SEARCH_CONNECTING;
 
266
 
 
267
        case LDAP_SERVER_DOWN:
 
268
down:;
 
269
                /* This is the worst thing that could happen:
 
270
                 * the search will wait until the retry is over. */
 
271
                if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) {
 
272
                        META_RETRYING_SET( &candidates[ candidate ] );
 
273
 
 
274
                        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
275
 
 
276
                        assert( mc->mc_refcnt > 0 );
 
277
                        if ( LogTest( LDAP_DEBUG_ANY ) ) {
 
278
                                char    buf[ SLAP_TEXT_BUFLEN ];
 
279
 
 
280
                                /* this lock is required; however,
 
281
                                 * it's invoked only when logging is on */
 
282
                                ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
 
283
                                snprintf( buf, sizeof( buf ),
 
284
                                        "retrying URI=\"%s\" DN=\"%s\"",
 
285
                                        mt->mt_uri,
 
286
                                        BER_BVISNULL( &msc->msc_bound_ndn ) ?
 
287
                                                "" : msc->msc_bound_ndn.bv_val );
 
288
                                ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
 
289
 
 
290
                                Debug( LDAP_DEBUG_ANY,
 
291
                                        "%s meta_search_dobind_init[%d]: %s.\n",
 
292
                                        op->o_log_prefix, candidate, buf );
 
293
                        }
 
294
 
 
295
                        meta_clear_one_candidate( op, mc, candidate );
 
296
                        LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
 
297
 
 
298
                        ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
 
299
 
 
300
                        /* mc here must be the regular mc, reset and ready for init */
 
301
                        rc = meta_back_init_one_conn( op, rs, mc, candidate,
 
302
                                LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
 
303
 
 
304
                        if ( rc == LDAP_SUCCESS ) {
 
305
                                LDAP_BACK_CONN_BINDING_SET( msc );
 
306
                        }
 
307
 
 
308
                        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
309
 
 
310
                        if ( rc == LDAP_SUCCESS ) {
 
311
                                candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
312
                                goto retry;
 
313
                        }
 
314
                }
 
315
 
 
316
                if ( *mcp == NULL ) {
 
317
                        retcode = META_SEARCH_ERR;
 
318
                        rs->sr_err = LDAP_UNAVAILABLE;
 
319
                        candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
320
                        break;
 
321
                }
 
322
                /* fall thru */
 
323
 
 
324
        default:
 
325
other:;
 
326
                rs->sr_err = rc;
 
327
                rc = slap_map_api2result( rs );
 
328
 
 
329
                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
330
                meta_clear_one_candidate( op, mc, candidate );
 
331
                candidates[ candidate ].sr_err = rc;
 
332
                if ( META_BACK_ONERR_STOP( mi ) ) {
 
333
                        LDAP_BACK_CONN_TAINTED_SET( mc );
 
334
                        meta_back_release_conn_lock( mi, mc, 0 );
 
335
                        *mcp = NULL;
 
336
                        rs->sr_err = rc;
 
337
 
 
338
                        retcode = META_SEARCH_ERR;
 
339
 
 
340
                } else {
 
341
                        retcode = META_SEARCH_NOT_CANDIDATE;
 
342
                }
 
343
                candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
344
                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
345
                break;
 
346
        }
 
347
 
 
348
        return retcode;
 
349
}
 
350
 
 
351
static meta_search_candidate_t
 
352
meta_search_dobind_result(
 
353
        Operation               *op,
 
354
        SlapReply               *rs,
 
355
        metaconn_t              **mcp,
 
356
        int                     candidate,
 
357
        SlapReply               *candidates,
 
358
        LDAPMessage             *res )
 
359
{
 
360
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
 
361
        metaconn_t              *mc = *mcp;
 
362
        metasingleconn_t        *msc = &mc->mc_conns[ candidate ];
 
363
 
 
364
        meta_search_candidate_t retcode = META_SEARCH_NOT_CANDIDATE;
 
365
        int                     rc;
 
366
 
 
367
        assert( msc->msc_ld != NULL );
 
368
 
 
369
        /* FIXME: matched? referrals? response controls? */
 
370
        rc = ldap_parse_result( msc->msc_ld, res,
 
371
                &candidates[ candidate ].sr_err,
 
372
                NULL, NULL, NULL, NULL, 0 );
 
373
        if ( rc != LDAP_SUCCESS ) {
 
374
                candidates[ candidate ].sr_err = rc;
 
375
 
 
376
        } else {
 
377
                rc = slap_map_api2result( &candidates[ candidate ] );
 
378
        }
 
379
 
 
380
        ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
381
        LDAP_BACK_CONN_BINDING_CLEAR( msc );
 
382
        if ( rc != LDAP_SUCCESS ) {
 
383
                meta_clear_one_candidate( op, mc, candidate );
 
384
                candidates[ candidate ].sr_err = rc;
 
385
                if ( META_BACK_ONERR_STOP( mi ) ) {
 
386
                        LDAP_BACK_CONN_TAINTED_SET( mc );
 
387
                        meta_back_release_conn_lock( mi, mc, 0 );
 
388
                        *mcp = NULL;
 
389
                        retcode = META_SEARCH_ERR;
 
390
                        rs->sr_err = rc;
 
391
                }
 
392
 
 
393
        } else {
 
394
                /* FIXME: check if bound as idassert authcDN! */
 
395
                if ( BER_BVISNULL( &msc->msc_bound_ndn )
 
396
                        || BER_BVISEMPTY( &msc->msc_bound_ndn ) )
 
397
                {
 
398
                        LDAP_BACK_CONN_ISANON_SET( msc );
 
399
 
 
400
                } else {
 
401
                        LDAP_BACK_CONN_ISBOUND_SET( msc );
 
402
                }
 
403
                retcode = META_SEARCH_CANDIDATE;
 
404
 
 
405
                /* connect must be async */
 
406
                ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
 
407
        }
 
408
 
 
409
        candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
410
        META_BINDING_CLEAR( &candidates[ candidate ] );
 
411
 
 
412
        ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
413
 
 
414
        return retcode;
 
415
}
 
416
 
 
417
static meta_search_candidate_t
 
418
meta_back_search_start(
 
419
        Operation               *op,
 
420
        SlapReply               *rs,
 
421
        dncookie                *dc,
 
422
        metaconn_t              **mcp,
 
423
        int                     candidate,
 
424
        SlapReply               *candidates )
 
425
{
 
426
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
 
427
        metatarget_t            *mt = mi->mi_targets[ candidate ];
 
428
        metasingleconn_t        *msc = &(*mcp)->mc_conns[ candidate ];
 
429
        struct berval           realbase = op->o_req_dn;
 
430
        int                     realscope = op->ors_scope;
 
431
        struct berval           mbase = BER_BVNULL; 
 
432
        struct berval           mfilter = BER_BVNULL;
 
433
        char                    **mapped_attrs = NULL;
 
434
        int                     rc;
 
435
        meta_search_candidate_t retcode;
 
436
        struct timeval          tv, *tvp = NULL;
 
437
        int                     nretries = 1;
 
438
        LDAPControl             **ctrls = NULL;
 
439
 
 
440
        /* this should not happen; just in case... */
 
441
        if ( msc->msc_ld == NULL ) {
 
442
                Debug( LDAP_DEBUG_ANY,
 
443
                        "%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
 
444
                        op->o_log_prefix, candidate,
 
445
                        META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
 
446
                candidates[ candidate ].sr_err = LDAP_OTHER;
 
447
                if ( META_BACK_ONERR_STOP( mi ) ) {
 
448
                        return META_SEARCH_ERR;
 
449
                }
 
450
                candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
451
                return META_SEARCH_NOT_CANDIDATE;
 
452
        }
 
453
 
 
454
        Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );
 
455
 
 
456
        /*
 
457
         * modifies the base according to the scope, if required
 
458
         */
 
459
        if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
 
460
                switch ( op->ors_scope ) {
 
461
                case LDAP_SCOPE_SUBTREE:
 
462
                        /*
 
463
                         * make the target suffix the new base
 
464
                         * FIXME: this is very forgiving, because
 
465
                         * "illegal" searchBases may be turned
 
466
                         * into the suffix of the target; however,
 
467
                         * the requested searchBase already passed
 
468
                         * thru the candidate analyzer...
 
469
                         */
 
470
                        if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
 
471
                                realbase = mt->mt_nsuffix;
 
472
                                if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
 
473
                                        realscope = LDAP_SCOPE_SUBORDINATE;
 
474
                                }
 
475
 
 
476
                        } else {
 
477
                                /*
 
478
                                 * this target is no longer candidate
 
479
                                 */
 
480
                                retcode = META_SEARCH_NOT_CANDIDATE;
 
481
                                goto doreturn;
 
482
                        }
 
483
                        break;
 
484
 
 
485
                case LDAP_SCOPE_SUBORDINATE:
 
486
                case LDAP_SCOPE_ONELEVEL:
 
487
                {
 
488
                        struct berval   rdn = mt->mt_nsuffix;
 
489
                        rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
 
490
                        if ( dnIsOneLevelRDN( &rdn )
 
491
                                        && dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
 
492
                        {
 
493
                                /*
 
494
                                 * if there is exactly one level,
 
495
                                 * make the target suffix the new
 
496
                                 * base, and make scope "base"
 
497
                                 */
 
498
                                realbase = mt->mt_nsuffix;
 
499
                                if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
 
500
                                        if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
 
501
                                                realscope = LDAP_SCOPE_SUBORDINATE;
 
502
                                        } else {
 
503
                                                realscope = LDAP_SCOPE_SUBTREE;
 
504
                                        }
 
505
                                } else {
 
506
                                        realscope = LDAP_SCOPE_BASE;
 
507
                                }
 
508
                                break;
 
509
                        } /* else continue with the next case */
 
510
                }
 
511
 
 
512
                case LDAP_SCOPE_BASE:
 
513
                        /*
 
514
                         * this target is no longer candidate
 
515
                         */
 
516
                        retcode = META_SEARCH_NOT_CANDIDATE;
 
517
                        goto doreturn;
 
518
                }
 
519
        }
 
520
 
 
521
        /* initiate dobind */
 
522
        retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );
 
523
 
 
524
        Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );
 
525
 
 
526
        if ( retcode != META_SEARCH_CANDIDATE ) {
 
527
                goto doreturn;
 
528
        }
 
529
 
 
530
        /*
 
531
         * Rewrite the search base, if required
 
532
         */
 
533
        dc->target = mt;
 
534
        dc->ctx = "searchBase";
 
535
        switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
 
536
        case LDAP_SUCCESS:
 
537
                break;
 
538
 
 
539
        case LDAP_UNWILLING_TO_PERFORM:
 
540
                rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
 
541
                rs->sr_text = "Operation not allowed";
 
542
                send_ldap_result( op, rs );
 
543
                retcode = META_SEARCH_ERR;
 
544
                goto doreturn;
 
545
 
 
546
        default:
 
547
 
 
548
                /*
 
549
                 * this target is no longer candidate
 
550
                 */
 
551
                retcode = META_SEARCH_NOT_CANDIDATE;
 
552
                goto doreturn;
 
553
        }
 
554
 
 
555
        /*
 
556
         * Maps filter
 
557
         */
 
558
        rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
 
559
                        &mfilter, BACKLDAP_MAP );
 
560
        switch ( rc ) {
 
561
        case LDAP_SUCCESS:
 
562
                break;
 
563
 
 
564
        case LDAP_COMPARE_FALSE:
 
565
        default:
 
566
                /*
 
567
                 * this target is no longer candidate
 
568
                 */
 
569
                retcode = META_SEARCH_NOT_CANDIDATE;
 
570
                goto done;
 
571
        }
 
572
 
 
573
        /*
 
574
         * Maps required attributes
 
575
         */
 
576
        rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at,
 
577
                        op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
 
578
        if ( rc != LDAP_SUCCESS ) {
 
579
                /*
 
580
                 * this target is no longer candidate
 
581
                 */
 
582
                retcode = META_SEARCH_NOT_CANDIDATE;
 
583
                goto done;
 
584
        }
 
585
 
 
586
        /* should we check return values? */
 
587
        if ( op->ors_deref != -1 ) {
 
588
                assert( msc->msc_ld != NULL );
 
589
                (void)ldap_set_option( msc->msc_ld, LDAP_OPT_DEREF,
 
590
                                ( void * )&op->ors_deref );
 
591
        }
 
592
 
 
593
        if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
 
594
                tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
 
595
                tv.tv_usec = 0;
 
596
                tvp = &tv;
 
597
        }
 
598
 
 
599
retry:;
 
600
        ctrls = op->o_ctrls;
 
601
        if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
 
602
                != LDAP_SUCCESS )
 
603
        {
 
604
                candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
605
                retcode = META_SEARCH_NOT_CANDIDATE;
 
606
                goto done;
 
607
        }
 
608
 
 
609
        /*
 
610
         * Starts the search
 
611
         */
 
612
        assert( msc->msc_ld != NULL );
 
613
        rc = ldap_search_ext( msc->msc_ld,
 
614
                        mbase.bv_val, realscope, mfilter.bv_val,
 
615
                        mapped_attrs, op->ors_attrsonly,
 
616
                        ctrls, NULL, tvp, op->ors_slimit,
 
617
                        &candidates[ candidate ].sr_msgid ); 
 
618
        switch ( rc ) {
 
619
        case LDAP_SUCCESS:
 
620
                retcode = META_SEARCH_CANDIDATE;
 
621
                break;
 
622
        
 
623
        case LDAP_SERVER_DOWN:
 
624
                if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
 
625
                        nretries = 0;
 
626
                        /* if the identity changed, there might be need to re-authz */
 
627
                        (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
 
628
                        goto retry;
 
629
                }
 
630
 
 
631
                if ( *mcp == NULL ) {
 
632
                        retcode = META_SEARCH_ERR;
 
633
                        candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
634
                        break;
 
635
                }
 
636
                /* fall thru */
 
637
 
 
638
        default:
 
639
                candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
 
640
                retcode = META_SEARCH_NOT_CANDIDATE;
 
641
        }
 
642
 
 
643
done:;
 
644
        (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
 
645
 
 
646
        if ( mapped_attrs ) {
 
647
                free( mapped_attrs );
 
648
        }
 
649
        if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
 
650
                free( mfilter.bv_val );
 
651
        }
 
652
        if ( mbase.bv_val != realbase.bv_val ) {
 
653
                free( mbase.bv_val );
 
654
        }
 
655
 
 
656
doreturn:;
 
657
        Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );
 
658
 
 
659
        return retcode;
 
660
}
 
661
 
 
662
int
 
663
meta_back_search( Operation *op, SlapReply *rs )
 
664
{
 
665
        metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
 
666
        metaconn_t      *mc;
 
667
        struct timeval  save_tv = { 0, 0 },
 
668
                        tv;
 
669
        time_t          stoptime = (time_t)(-1),
 
670
                        lastres_time = slap_get_time(),
 
671
                        timeout = 0;
 
672
        int             rc = 0, sres = LDAP_SUCCESS;
 
673
        char            *matched = NULL;
 
674
        int             last = 0, ncandidates = 0,
 
675
                        initial_candidates = 0, candidate_match = 0,
 
676
                        needbind = 0;
 
677
        ldap_back_send_t        sendok = LDAP_BACK_SENDERR;
 
678
        long            i;
 
679
        dncookie        dc;
 
680
        int             is_ok = 0;
 
681
        void            *savepriv;
 
682
        SlapReply       *candidates = NULL;
 
683
 
 
684
        /*
 
685
         * controls are set in ldap_back_dobind()
 
686
         * 
 
687
         * FIXME: in case of values return filter, we might want
 
688
         * to map attrs and maybe rewrite value
 
689
         */
 
690
getconn:;
 
691
        mc = meta_back_getconn( op, rs, NULL, sendok );
 
692
        if ( !mc ) {
 
693
                return rs->sr_err;
 
694
        }
 
695
 
 
696
        dc.conn = op->o_conn;
 
697
        dc.rs = rs;
 
698
 
 
699
        if ( candidates == NULL ) candidates = meta_back_candidates_get( op );
 
700
        /*
 
701
         * Inits searches
 
702
         */
 
703
        for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
704
                /* reset sr_msgid; it is used in most loops
 
705
                 * to check if that target is still to be considered */
 
706
                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
707
 
 
708
                /* a target is marked as candidate by meta_back_getconn();
 
709
                 * if for any reason (an error, it's over or so) it is
 
710
                 * no longer active, sr_msgid is set to META_MSGID_IGNORE
 
711
                 * but it remains candidate, which means it has been active
 
712
                 * at some point during the operation.  This allows to 
 
713
                 * use its response code and more to compute the final
 
714
                 * response */
 
715
                if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
 
716
                        continue;
 
717
                }
 
718
 
 
719
                candidates[ i ].sr_matched = NULL;
 
720
                candidates[ i ].sr_text = NULL;
 
721
                candidates[ i ].sr_ref = NULL;
 
722
                candidates[ i ].sr_ctrls = NULL;
 
723
 
 
724
                /* get largest timeout among candidates */
 
725
                if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
 
726
                        && mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout )
 
727
                {
 
728
                        timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ];
 
729
                }
 
730
        }
 
731
 
 
732
        for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
733
                if ( !META_IS_CANDIDATE( &candidates[ i ] )
 
734
                        || candidates[ i ].sr_err != LDAP_SUCCESS )
 
735
                {
 
736
                        continue;
 
737
                }
 
738
 
 
739
                switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
 
740
                {
 
741
                case META_SEARCH_NOT_CANDIDATE:
 
742
                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
743
                        break;
 
744
 
 
745
                case META_SEARCH_NEED_BIND:
 
746
                        ++needbind;
 
747
                        /* fallthru */
 
748
 
 
749
                case META_SEARCH_CONNECTING:
 
750
                case META_SEARCH_CANDIDATE:
 
751
                case META_SEARCH_BINDING:
 
752
                        candidates[ i ].sr_type = REP_INTERMEDIATE;
 
753
                        ++ncandidates;
 
754
                        break;
 
755
 
 
756
                case META_SEARCH_ERR:
 
757
                        savepriv = op->o_private;
 
758
                        op->o_private = (void *)i;
 
759
                        send_ldap_result( op, rs );
 
760
                        op->o_private = savepriv;
 
761
                        rc = -1;
 
762
                        goto finish;
 
763
 
 
764
                default:
 
765
                        assert( 0 );
 
766
                        break;
 
767
                }
 
768
        }
 
769
 
 
770
        if ( ncandidates > 0 && needbind == ncandidates ) {
 
771
                /*
 
772
                 * give up the second time...
 
773
                 *
 
774
                 * NOTE: this should not occur the second time, since a fresh
 
775
                 * connection has ben created; however, targets may also
 
776
                 * need bind because the bind timed out or so.
 
777
                 */
 
778
                if ( sendok & LDAP_BACK_BINDING ) {
 
779
                        Debug( LDAP_DEBUG_ANY,
 
780
                                "%s meta_back_search: unable to initialize conn\n",
 
781
                                op->o_log_prefix, 0, 0 );
 
782
                        rs->sr_err = LDAP_UNAVAILABLE;
 
783
                        rs->sr_text = "unable to initialize connection to remote targets";
 
784
                        send_ldap_result( op, rs );
 
785
                        rc = -1;
 
786
                        goto finish;
 
787
                }
 
788
 
 
789
                /* FIXME: better create a separate connection? */
 
790
                sendok |= LDAP_BACK_BINDING;
 
791
 
 
792
#ifdef DEBUG_205
 
793
                Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
 
794
                        op->o_log_prefix, (void *)mc, 0 );
 
795
#endif /* DEBUG_205 */
 
796
 
 
797
                meta_back_release_conn( mi, mc );
 
798
                mc = NULL;
 
799
 
 
800
                needbind = 0;
 
801
                ncandidates = 0;
 
802
 
 
803
                goto getconn;
 
804
        }
 
805
 
 
806
        initial_candidates = ncandidates;
 
807
 
 
808
        if ( LogTest( LDAP_DEBUG_TRACE ) ) {
 
809
                char    cnd[ SLAP_TEXT_BUFLEN ];
 
810
                int     c;
 
811
 
 
812
                for ( c = 0; c < mi->mi_ntargets; c++ ) {
 
813
                        if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
 
814
                                cnd[ c ] = '*';
 
815
                        } else {
 
816
                                cnd[ c ] = ' ';
 
817
                        }
 
818
                }
 
819
                cnd[ c ] = '\0';
 
820
 
 
821
                Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
 
822
                        "cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
 
823
        }
 
824
 
 
825
        if ( initial_candidates == 0 ) {
 
826
                /* NOTE: here we are not sending any matchedDN;
 
827
                 * this is intended, because if the back-meta
 
828
                 * is serving this search request, but no valid
 
829
                 * candidate could be looked up, it means that
 
830
                 * there is a hole in the mapping of the targets
 
831
                 * and thus no knowledge of any remote superior
 
832
                 * is available */
 
833
                Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
 
834
                        "base=\"%s\" scope=%d: "
 
835
                        "no candidate could be selected\n",
 
836
                        op->o_log_prefix, op->o_req_dn.bv_val,
 
837
                        op->ors_scope );
 
838
 
 
839
                /* FIXME: we're sending the first error we encounter;
 
840
                 * maybe we should pick the worst... */
 
841
                rc = LDAP_NO_SUCH_OBJECT;
 
842
                for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
843
                        if ( META_IS_CANDIDATE( &candidates[ i ] )
 
844
                                && candidates[ i ].sr_err != LDAP_SUCCESS )
 
845
                        {
 
846
                                rc = candidates[ i ].sr_err;
 
847
                                break;
 
848
                        }
 
849
                }
 
850
 
 
851
                send_ldap_error( op, rs, rc, NULL );
 
852
 
 
853
                goto finish;
 
854
        }
 
855
 
 
856
        /* We pull apart the ber result, stuff it into a slapd entry, and
 
857
         * let send_search_entry stuff it back into ber format. Slow & ugly,
 
858
         * but this is necessary for version matching, and for ACL processing.
 
859
         */
 
860
 
 
861
        if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
 
862
                stoptime = op->o_time + op->ors_tlimit;
 
863
        }
 
864
 
 
865
        /*
 
866
         * In case there are no candidates, no cycle takes place...
 
867
         *
 
868
         * FIXME: we might use a queue, to better balance the load 
 
869
         * among the candidates
 
870
         */
 
871
        for ( rc = 0; ncandidates > 0; ) {
 
872
                int     gotit = 0,
 
873
                        doabandon = 0,
 
874
                        alreadybound = ncandidates;
 
875
 
 
876
                /* check timeout */
 
877
                if ( timeout && lastres_time > 0
 
878
                        && ( slap_get_time() - lastres_time ) > timeout )
 
879
                {
 
880
                        doabandon = 1;
 
881
                        rs->sr_text = "Operation timed out";
 
882
                        rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
 
883
                                LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
 
884
                        savepriv = op->o_private;
 
885
                        op->o_private = (void *)i;
 
886
                        send_ldap_result( op, rs );
 
887
                        op->o_private = savepriv;
 
888
                        goto finish;
 
889
                }
 
890
 
 
891
                /* check time limit */
 
892
                if ( op->ors_tlimit != SLAP_NO_LIMIT
 
893
                                && slap_get_time() > stoptime )
 
894
                {
 
895
                        doabandon = 1;
 
896
                        rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
 
897
                        savepriv = op->o_private;
 
898
                        op->o_private = (void *)i;
 
899
                        send_ldap_result( op, rs );
 
900
                        op->o_private = savepriv;
 
901
                        goto finish;
 
902
                }
 
903
 
 
904
                for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
905
                        meta_search_candidate_t retcode = META_SEARCH_UNDEFINED;
 
906
                        metasingleconn_t        *msc = &mc->mc_conns[ i ];
 
907
                        LDAPMessage             *res = NULL, *msg;
 
908
 
 
909
                        /* if msgid is invalid, don't ldap_result() */
 
910
                        if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
 
911
                                continue;
 
912
                        }
 
913
 
 
914
                        /* if target still needs bind, retry */
 
915
                        if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND
 
916
                                || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
 
917
                        {
 
918
                                /* initiate dobind */
 
919
                                retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );
 
920
 
 
921
                                Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
 
922
                                        op->o_log_prefix, i, retcode );
 
923
 
 
924
                                switch ( retcode ) {
 
925
                                case META_SEARCH_NEED_BIND:
 
926
                                        alreadybound--;
 
927
                                        /* fallthru */
 
928
 
 
929
                                case META_SEARCH_CONNECTING:
 
930
                                case META_SEARCH_BINDING:
 
931
                                        break;
 
932
 
 
933
                                case META_SEARCH_ERR:
 
934
                                        candidates[ i ].sr_err = rs->sr_err;
 
935
                                        if ( META_BACK_ONERR_STOP( mi ) ) {
 
936
                                                savepriv = op->o_private;
 
937
                                                op->o_private = (void *)i;
 
938
                                                send_ldap_result( op, rs );
 
939
                                                op->o_private = savepriv;
 
940
                                                goto finish;
 
941
                                        }
 
942
                                        /* fallthru */
 
943
 
 
944
                                case META_SEARCH_NOT_CANDIDATE:
 
945
                                        /*
 
946
                                         * When no candidates are left,
 
947
                                         * the outer cycle finishes
 
948
                                         */
 
949
                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
950
                                        assert( ncandidates > 0 );
 
951
                                        --ncandidates;
 
952
                                        break;
 
953
 
 
954
                                case META_SEARCH_CANDIDATE:
 
955
                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
956
                                        switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
 
957
                                        {
 
958
                                        case META_SEARCH_CANDIDATE:
 
959
                                                assert( candidates[ i ].sr_msgid >= 0 );
 
960
                                                break;
 
961
 
 
962
                                        case META_SEARCH_ERR:
 
963
                                                candidates[ i ].sr_err = rs->sr_err;
 
964
                                                if ( META_BACK_ONERR_STOP( mi ) ) {
 
965
                                                        savepriv = op->o_private;
 
966
                                                        op->o_private = (void *)i;
 
967
                                                        send_ldap_result( op, rs );
 
968
                                                        op->o_private = savepriv;
 
969
                                                        goto finish;
 
970
                                                }
 
971
                                                /* fallthru */
 
972
 
 
973
                                        case META_SEARCH_NOT_CANDIDATE:
 
974
                                                /* means that meta_back_search_start()
 
975
                                                 * failed but onerr == continue */
 
976
                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
977
                                                assert( ncandidates > 0 );
 
978
                                                --ncandidates;
 
979
                                                break;
 
980
 
 
981
                                        default:
 
982
                                                /* impossible */
 
983
                                                assert( 0 );
 
984
                                                break;
 
985
                                        }
 
986
                                        break;
 
987
 
 
988
                                default:
 
989
                                        /* impossible */
 
990
                                        assert( 0 );
 
991
                                        break;
 
992
                                }
 
993
                                continue;
 
994
                        }
 
995
 
 
996
                        /* check for abandon */
 
997
                        if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
 
998
                                break;
 
999
                        }
 
1000
 
 
1001
#ifdef DEBUG_205
 
1002
                        if ( msc->msc_ld == NULL ) {
 
1003
                                char    buf[ SLAP_TEXT_BUFLEN ];
 
1004
 
 
1005
                                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
1006
                                snprintf( buf, sizeof( buf ),
 
1007
                                        "%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
 
1008
                                        op->o_log_prefix, (long)i, (void *)mc,
 
1009
                                        candidates[ i ].sr_msgid,
 
1010
                                        META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
 
1011
                                        LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
 
1012
                                        META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
 
1013
                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
1014
                                        
 
1015
                                Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
 
1016
                        }
 
1017
#endif /* DEBUG_205 */
 
1018
                        
 
1019
                        /*
 
1020
                         * FIXME: handle time limit as well?
 
1021
                         * Note that target servers are likely 
 
1022
                         * to handle it, so at some time we'll
 
1023
                         * get a LDAP_TIMELIMIT_EXCEEDED from
 
1024
                         * one of them ...
 
1025
                         */
 
1026
                        tv = save_tv;
 
1027
                        rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
 
1028
                                        LDAP_MSG_RECEIVED, &tv, &res );
 
1029
                        switch ( rc ) {
 
1030
                        case 0:
 
1031
                                /* FIXME: res should not need to be freed */
 
1032
                                assert( res == NULL );
 
1033
                                continue;
 
1034
 
 
1035
                        case -1:
 
1036
really_bad:;
 
1037
                                /* something REALLY bad happened! */
 
1038
                                if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
 
1039
                                        candidates[ i ].sr_type = REP_RESULT;
 
1040
 
 
1041
                                        if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
 
1042
                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1043
                                                switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
 
1044
                                                {
 
1045
                                                        /* means that failed but onerr == continue */
 
1046
                                                case META_SEARCH_NOT_CANDIDATE:
 
1047
                                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1048
 
 
1049
                                                        assert( ncandidates > 0 );
 
1050
                                                        --ncandidates;
 
1051
 
 
1052
                                                        candidates[ i ].sr_err = rs->sr_err;
 
1053
                                                        if ( META_BACK_ONERR_STOP( mi ) ) {
 
1054
                                                                savepriv = op->o_private;
 
1055
                                                                op->o_private = (void *)i;
 
1056
                                                                send_ldap_result( op, rs );
 
1057
                                                                op->o_private = savepriv;
 
1058
                                                                goto finish;
 
1059
                                                        }
 
1060
                                                        /* fall thru */
 
1061
 
 
1062
                                                case META_SEARCH_CANDIDATE:
 
1063
                                                        /* get back into business... */
 
1064
                                                        continue;
 
1065
 
 
1066
                                                case META_SEARCH_BINDING:
 
1067
                                                case META_SEARCH_CONNECTING:
 
1068
                                                case META_SEARCH_NEED_BIND:
 
1069
                                                case META_SEARCH_UNDEFINED:
 
1070
                                                        assert( 0 );
 
1071
 
 
1072
                                                default:
 
1073
                                                        /* unrecoverable error */
 
1074
                                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1075
                                                        rc = rs->sr_err = LDAP_OTHER;
 
1076
                                                        goto finish;
 
1077
                                                }
 
1078
                                        }
 
1079
 
 
1080
                                        candidates[ i ].sr_err = rs->sr_err;
 
1081
                                        if ( META_BACK_ONERR_STOP( mi ) ) {
 
1082
                                                savepriv = op->o_private;
 
1083
                                                op->o_private = (void *)i;
 
1084
                                                send_ldap_result( op, rs );
 
1085
                                                op->o_private = savepriv;
 
1086
                                                goto finish;
 
1087
                                        }
 
1088
                                }
 
1089
 
 
1090
                                /*
 
1091
                                 * When no candidates are left,
 
1092
                                 * the outer cycle finishes
 
1093
                                 */
 
1094
                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1095
                                assert( ncandidates > 0 );
 
1096
                                --ncandidates;
 
1097
                                rs->sr_err = candidates[ i ].sr_err;
 
1098
                                continue;
 
1099
 
 
1100
                        default:
 
1101
                                lastres_time = slap_get_time();
 
1102
 
 
1103
                                /* only touch when activity actually took place... */
 
1104
                                if ( mi->mi_idle_timeout != 0 && msc->msc_time < lastres_time ) {
 
1105
                                        msc->msc_time = lastres_time;
 
1106
                                }
 
1107
                                break;
 
1108
                        }
 
1109
 
 
1110
                        for ( msg = ldap_first_message( msc->msc_ld, res );
 
1111
                                msg != NULL;
 
1112
                                msg = ldap_next_message( msc->msc_ld, msg ) )
 
1113
                        {
 
1114
                                rc = ldap_msgtype( msg );
 
1115
                                if ( rc == LDAP_RES_SEARCH_ENTRY ) {
 
1116
                                        LDAPMessage     *e;
 
1117
 
 
1118
                                        if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
 
1119
                                                /* don't retry any more... */
 
1120
                                                candidates[ i ].sr_type = REP_RESULT;
 
1121
                                        }
 
1122
 
 
1123
                                        is_ok++;
 
1124
 
 
1125
                                        e = ldap_first_entry( msc->msc_ld, msg );
 
1126
                                        savepriv = op->o_private;
 
1127
                                        op->o_private = (void *)i;
 
1128
                                        rs->sr_err = meta_send_entry( op, rs, mc, i, e );
 
1129
 
 
1130
                                        switch ( rs->sr_err ) {
 
1131
                                        case LDAP_SIZELIMIT_EXCEEDED:
 
1132
                                                savepriv = op->o_private;
 
1133
                                                op->o_private = (void *)i;
 
1134
                                                send_ldap_result( op, rs );
 
1135
                                                op->o_private = savepriv;
 
1136
                                                rs->sr_err = LDAP_SUCCESS;
 
1137
                                                ldap_msgfree( res );
 
1138
                                                res = NULL;
 
1139
                                                goto finish;
 
1140
 
 
1141
                                        case LDAP_UNAVAILABLE:
 
1142
                                                rs->sr_err = LDAP_OTHER;
 
1143
                                                ldap_msgfree( res );
 
1144
                                                res = NULL;
 
1145
                                                goto finish;
 
1146
                                        }
 
1147
                                        op->o_private = savepriv;
 
1148
 
 
1149
                                        /* don't wait any longer... */
 
1150
                                        gotit = 1;
 
1151
                                        save_tv.tv_sec = 0;
 
1152
                                        save_tv.tv_usec = 0;
 
1153
 
 
1154
                                } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
 
1155
                                        char            **references = NULL;
 
1156
                                        int             cnt;
 
1157
 
 
1158
                                        if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
 
1159
                                                /* don't retry any more... */
 
1160
                                                candidates[ i ].sr_type = REP_RESULT;
 
1161
                                        }
 
1162
        
 
1163
                                        is_ok++;
 
1164
        
 
1165
                                        rc = ldap_parse_reference( msc->msc_ld, msg,
 
1166
                                                        &references, &rs->sr_ctrls, 0 );
 
1167
        
 
1168
                                        if ( rc != LDAP_SUCCESS ) {
 
1169
                                                continue;
 
1170
                                        }
 
1171
        
 
1172
                                        if ( references == NULL ) {
 
1173
                                                continue;
 
1174
                                        }
 
1175
 
 
1176
#ifdef ENABLE_REWRITE
 
1177
                                        dc.ctx = "referralDN";
 
1178
#else /* ! ENABLE_REWRITE */
 
1179
                                        dc.tofrom = 0;
 
1180
                                        dc.normalized = 0;
 
1181
#endif /* ! ENABLE_REWRITE */
 
1182
 
 
1183
                                        /* FIXME: merge all and return at the end */
 
1184
        
 
1185
                                        for ( cnt = 0; references[ cnt ]; cnt++ )
 
1186
                                                ;
 
1187
        
 
1188
                                        rs->sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
 
1189
        
 
1190
                                        for ( cnt = 0; references[ cnt ]; cnt++ ) {
 
1191
                                                ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] );
 
1192
                                        }
 
1193
                                        BER_BVZERO( &rs->sr_ref[ cnt ] );
 
1194
        
 
1195
                                        ( void )ldap_back_referral_result_rewrite( &dc, rs->sr_ref );
 
1196
 
 
1197
                                        if ( rs->sr_ref != NULL && !BER_BVISNULL( &rs->sr_ref[ 0 ] ) ) {
 
1198
                                                /* ignore return value by now */
 
1199
                                                savepriv = op->o_private;
 
1200
                                                op->o_private = (void *)i;
 
1201
                                                ( void )send_search_reference( op, rs );
 
1202
                                                op->o_private = savepriv;
 
1203
        
 
1204
                                                ber_bvarray_free( rs->sr_ref );
 
1205
                                                rs->sr_ref = NULL;
 
1206
                                        }
 
1207
 
 
1208
                                        /* cleanup */
 
1209
                                        if ( references ) {
 
1210
                                                ber_memvfree( (void **)references );
 
1211
                                        }
 
1212
 
 
1213
                                        if ( rs->sr_ctrls ) {
 
1214
                                                ldap_controls_free( rs->sr_ctrls );
 
1215
                                                rs->sr_ctrls = NULL;
 
1216
                                        }
 
1217
 
 
1218
                                } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
 
1219
                                        char            buf[ SLAP_TEXT_BUFLEN ];
 
1220
                                        char            **references = NULL;
 
1221
 
 
1222
                                        if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
 
1223
                                                /* don't retry any more... */
 
1224
                                                candidates[ i ].sr_type = REP_RESULT;
 
1225
                                        }
 
1226
        
 
1227
                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1228
 
 
1229
                                        /* NOTE: ignores response controls
 
1230
                                         * (and intermediate response controls
 
1231
                                         * as well, except for those with search
 
1232
                                         * references); this may not be correct,
 
1233
                                         * but if they're not ignored then
 
1234
                                         * back-meta would need to merge them
 
1235
                                         * consistently (think of pagedResults...)
 
1236
                                         */
 
1237
                                        /* FIXME: response controls? */
 
1238
                                        rs->sr_err = ldap_parse_result( msc->msc_ld,
 
1239
                                                msg,
 
1240
                                                &candidates[ i ].sr_err,
 
1241
                                                (char **)&candidates[ i ].sr_matched,
 
1242
                                                NULL /* (char **)&candidates[ i ].sr_text */ ,
 
1243
                                                &references,
 
1244
                                                NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
 
1245
                                                0 );
 
1246
                                        if ( rs->sr_err != LDAP_SUCCESS ) {
 
1247
                                                sres = slap_map_api2result( &candidates[ i ] );
 
1248
                                                candidates[ i ].sr_type = REP_RESULT;
 
1249
                                                ldap_msgfree( res );
 
1250
                                                res = NULL;
 
1251
                                                goto really_bad;
 
1252
                                        }
 
1253
 
 
1254
                                        rs->sr_err = candidates[ i ].sr_err;
 
1255
 
 
1256
                                        /* massage matchedDN if need be */
 
1257
                                        if ( candidates[ i ].sr_matched != NULL ) {
 
1258
                                                struct berval   match, mmatch;
 
1259
 
 
1260
                                                ber_str2bv( candidates[ i ].sr_matched,
 
1261
                                                        0, 0, &match );
 
1262
                                                candidates[ i ].sr_matched = NULL;
 
1263
 
 
1264
                                                dc.ctx = "matchedDN";
 
1265
                                                dc.target = mi->mi_targets[ i ];
 
1266
                                                if ( !ldap_back_dn_massage( &dc, &match, &mmatch ) ) {
 
1267
                                                        if ( mmatch.bv_val == match.bv_val ) {
 
1268
                                                                candidates[ i ].sr_matched
 
1269
                                                                        = ch_strdup( mmatch.bv_val );
 
1270
 
 
1271
                                                        } else {
 
1272
                                                                candidates[ i ].sr_matched = mmatch.bv_val;
 
1273
                                                        }
 
1274
 
 
1275
                                                        candidate_match++;
 
1276
                                                } 
 
1277
                                                ldap_memfree( match.bv_val );
 
1278
                                        }
 
1279
 
 
1280
                                        /* add references to array */
 
1281
                                        /* RFC 4511: referrals can only appear
 
1282
                                         * if result code is LDAP_REFERRAL */
 
1283
                                        if ( references != NULL
 
1284
                                                && references[ 0 ] != NULL
 
1285
                                                && references[ 0 ][ 0 ] != '\0' )
 
1286
                                        {
 
1287
                                                if ( rs->sr_err != LDAP_REFERRAL ) {
 
1288
                                                        Debug( LDAP_DEBUG_ANY,
 
1289
                                                                "%s meta_back_search[%ld]: "
 
1290
                                                                "got referrals with err=%d\n",
 
1291
                                                                op->o_log_prefix,
 
1292
                                                                i, rs->sr_err );
 
1293
 
 
1294
                                                } else {
 
1295
                                                        BerVarray       sr_ref;
 
1296
                                                        int             cnt;
 
1297
        
 
1298
                                                        for ( cnt = 0; references[ cnt ]; cnt++ )
 
1299
                                                                ;
 
1300
        
 
1301
                                                        sr_ref = ch_calloc( sizeof( struct berval ), cnt + 1 );
 
1302
        
 
1303
                                                        for ( cnt = 0; references[ cnt ]; cnt++ ) {
 
1304
                                                                ber_str2bv( references[ cnt ], 0, 1, &sr_ref[ cnt ] );
 
1305
                                                        }
 
1306
                                                        BER_BVZERO( &sr_ref[ cnt ] );
 
1307
        
 
1308
                                                        ( void )ldap_back_referral_result_rewrite( &dc, sr_ref );
 
1309
                                        
 
1310
                                                        if ( rs->sr_v2ref == NULL ) {
 
1311
                                                                rs->sr_v2ref = sr_ref;
 
1312
 
 
1313
                                                        } else {
 
1314
                                                                for ( cnt = 0; !BER_BVISNULL( &sr_ref[ cnt ] ); cnt++ ) {
 
1315
                                                                        ber_bvarray_add( &rs->sr_v2ref, &sr_ref[ cnt ] );
 
1316
                                                                }
 
1317
                                                                ber_memfree( sr_ref );
 
1318
                                                        }
 
1319
                                                }
 
1320
 
 
1321
                                        } else if ( rs->sr_err == LDAP_REFERRAL ) {
 
1322
                                                Debug( LDAP_DEBUG_ANY,
 
1323
                                                        "%s meta_back_search[%ld]: "
 
1324
                                                        "got err=%d with null "
 
1325
                                                        "or empty referrals\n",
 
1326
                                                        op->o_log_prefix,
 
1327
                                                        i, rs->sr_err );
 
1328
 
 
1329
                                                rs->sr_err = LDAP_NO_SUCH_OBJECT;
 
1330
                                        }
 
1331
 
 
1332
                                        /* cleanup */
 
1333
                                        ber_memvfree( (void **)references );
 
1334
        
 
1335
                                        sres = slap_map_api2result( rs );
 
1336
        
 
1337
                                        if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
 
1338
                                                snprintf( buf, sizeof( buf ),
 
1339
                                                        "%s meta_back_search[%ld] "
 
1340
                                                        "match=\"%s\" err=%ld",
 
1341
                                                        op->o_log_prefix, i,
 
1342
                                                        candidates[ i ].sr_matched ? candidates[ i ].sr_matched : "",
 
1343
                                                        (long) candidates[ i ].sr_err );
 
1344
                                                if ( candidates[ i ].sr_err == LDAP_SUCCESS ) {
 
1345
                                                        Debug( LDAP_DEBUG_TRACE, "%s.\n", buf, 0, 0 );
 
1346
        
 
1347
                                                } else {
 
1348
                                                        Debug( LDAP_DEBUG_ANY, "%s (%s).\n",
 
1349
                                                                buf, ldap_err2string( candidates[ i ].sr_err ), 0 );
 
1350
                                                }
 
1351
                                        }
 
1352
        
 
1353
                                        switch ( sres ) {
 
1354
                                        case LDAP_NO_SUCH_OBJECT:
 
1355
                                                /* is_ok is touched any time a valid
 
1356
                                                 * (even intermediate) result is
 
1357
                                                 * returned; as a consequence, if
 
1358
                                                 * a candidate returns noSuchObject
 
1359
                                                 * it is ignored and the candidate
 
1360
                                                 * is simply demoted. */
 
1361
                                                if ( is_ok ) {
 
1362
                                                        sres = LDAP_SUCCESS;
 
1363
                                                }
 
1364
                                                break;
 
1365
        
 
1366
                                        case LDAP_SUCCESS:
 
1367
                                        case LDAP_REFERRAL:
 
1368
                                                is_ok++;
 
1369
                                                break;
 
1370
        
 
1371
                                        case LDAP_SIZELIMIT_EXCEEDED:
 
1372
                                                /* if a target returned sizelimitExceeded
 
1373
                                                 * and the entry count is equal to the
 
1374
                                                 * proxy's limit, the target would have
 
1375
                                                 * returned more, and the error must be
 
1376
                                                 * propagated to the client; otherwise,
 
1377
                                                 * the target enforced a limit lower
 
1378
                                                 * than what requested by the proxy;
 
1379
                                                 * ignore it */
 
1380
                                                candidates[ i ].sr_err = rs->sr_err;
 
1381
                                                if ( rs->sr_nentries == op->ors_slimit
 
1382
                                                        || META_BACK_ONERR_STOP( mi ) )
 
1383
                                                {
 
1384
                                                        savepriv = op->o_private;
 
1385
                                                        op->o_private = (void *)i;
 
1386
                                                        send_ldap_result( op, rs );
 
1387
                                                        op->o_private = savepriv;
 
1388
                                                        ldap_msgfree( res );
 
1389
                                                        res = NULL;
 
1390
                                                        goto finish;
 
1391
                                                }
 
1392
                                                break;
 
1393
        
 
1394
                                        default:
 
1395
                                                candidates[ i ].sr_err = rs->sr_err;
 
1396
                                                if ( META_BACK_ONERR_STOP( mi ) ) {
 
1397
                                                        savepriv = op->o_private;
 
1398
                                                        op->o_private = (void *)i;
 
1399
                                                        send_ldap_result( op, rs );
 
1400
                                                        op->o_private = savepriv;
 
1401
                                                        ldap_msgfree( res );
 
1402
                                                        res = NULL;
 
1403
                                                        goto finish;
 
1404
                                                }
 
1405
                                                break;
 
1406
                                        }
 
1407
        
 
1408
                                        last = i;
 
1409
                                        rc = 0;
 
1410
        
 
1411
                                        /*
 
1412
                                         * When no candidates are left,
 
1413
                                         * the outer cycle finishes
 
1414
                                         */
 
1415
                                        assert( ncandidates > 0 );
 
1416
                                        --ncandidates;
 
1417
        
 
1418
                                } else if ( rc == LDAP_RES_BIND ) {
 
1419
                                        meta_search_candidate_t retcode;
 
1420
        
 
1421
                                        retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
 
1422
                                        if ( retcode == META_SEARCH_CANDIDATE ) {
 
1423
                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1424
                                                retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
 
1425
                                        }
 
1426
        
 
1427
                                        switch ( retcode ) {
 
1428
                                        case META_SEARCH_CANDIDATE:
 
1429
                                                break;
 
1430
        
 
1431
                                                /* means that failed but onerr == continue */
 
1432
                                        case META_SEARCH_NOT_CANDIDATE:
 
1433
                                        case META_SEARCH_ERR:
 
1434
                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1435
                                                assert( ncandidates > 0 );
 
1436
                                                --ncandidates;
 
1437
        
 
1438
                                                candidates[ i ].sr_err = rs->sr_err;
 
1439
                                                if ( META_BACK_ONERR_STOP( mi ) ) {
 
1440
                                                        savepriv = op->o_private;
 
1441
                                                        op->o_private = (void *)i;
 
1442
                                                        send_ldap_result( op, rs );
 
1443
                                                        op->o_private = savepriv;
 
1444
                                                        ldap_msgfree( res );
 
1445
                                                        res = NULL;
 
1446
                                                        goto finish;
 
1447
                                                }
 
1448
                                                goto free_message;
 
1449
        
 
1450
                                        default:
 
1451
                                                assert( 0 );
 
1452
                                                break;
 
1453
                                        }
 
1454
        
 
1455
                                } else {
 
1456
                                        assert( 0 );
 
1457
                                        ldap_msgfree( res );
 
1458
                                        res = NULL;
 
1459
                                        goto really_bad;
 
1460
                                }
 
1461
                        }
 
1462
 
 
1463
free_message:;
 
1464
                        ldap_msgfree( res );
 
1465
                        res = NULL;
 
1466
                }
 
1467
 
 
1468
                /* check for abandon */
 
1469
                if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
 
1470
                        for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
1471
                                if ( candidates[ i ].sr_msgid >= 0
 
1472
                                        || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
 
1473
                                {
 
1474
                                        if ( META_IS_BINDING( &candidates[ i ] )
 
1475
                                                || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
 
1476
                                        {
 
1477
                                                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
1478
                                                if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
 
1479
                                                        || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
 
1480
                                                {
 
1481
                                                        /* if still binding, destroy */
 
1482
 
 
1483
#ifdef DEBUG_205
 
1484
                                                        char buf[ SLAP_TEXT_BUFLEN ];
 
1485
 
 
1486
                                                        snprintf( buf, sizeof( buf), "%s meta_back_search(abandon) "
 
1487
                                                                "ldap_unbind_ext[%ld] mc=%p ld=%p",
 
1488
                                                                op->o_log_prefix, i, (void *)mc,
 
1489
                                                                (void *)mc->mc_conns[i].msc_ld );
 
1490
 
 
1491
                                                        Debug( LDAP_DEBUG_ANY, "### %s\n", buf, 0, 0 );
 
1492
#endif /* DEBUG_205 */
 
1493
 
 
1494
                                                        meta_clear_one_candidate( op, mc, i );
 
1495
                                                }
 
1496
                                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
1497
                                                META_BINDING_CLEAR( &candidates[ i ] );
 
1498
                                                
 
1499
                                        } else {
 
1500
                                                (void)meta_back_cancel( mc, op, rs,
 
1501
                                                        candidates[ i ].sr_msgid, i,
 
1502
                                                        LDAP_BACK_DONTSEND );
 
1503
                                        }
 
1504
 
 
1505
                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
 
1506
                                        assert( ncandidates > 0 );
 
1507
                                        --ncandidates;
 
1508
                                }
 
1509
                        }
 
1510
 
 
1511
                        if ( op->o_abandon ) {
 
1512
                                rc = SLAPD_ABANDON;
 
1513
                        }
 
1514
 
 
1515
                        /* let send_ldap_result play cleanup handlers (ITS#4645) */
 
1516
                        break;
 
1517
                }
 
1518
 
 
1519
                /* if no entry was found during this loop,
 
1520
                 * set a minimal timeout */
 
1521
                if ( ncandidates > 0 && gotit == 0 ) {
 
1522
                        if ( save_tv.tv_sec == 0 && save_tv.tv_usec == 0 ) {
 
1523
                                save_tv.tv_usec = LDAP_BACK_RESULT_UTIMEOUT/initial_candidates;
 
1524
 
 
1525
                                /* arbitrarily limit to something between 1 and 2 minutes */
 
1526
                        } else if ( ( stoptime == -1 && save_tv.tv_sec < 60 )
 
1527
                                || save_tv.tv_sec < ( stoptime - slap_get_time() ) / ( 2 * ncandidates ) )
 
1528
                        {
 
1529
                                /* double the timeout */
 
1530
                                lutil_timermul( &save_tv, 2, &save_tv );
 
1531
                        }
 
1532
 
 
1533
                        if ( alreadybound == 0 ) {
 
1534
                                tv = save_tv;
 
1535
                                (void)select( 0, NULL, NULL, NULL, &tv );
 
1536
 
 
1537
                        } else {
 
1538
                                ldap_pvt_thread_yield();
 
1539
                        }
 
1540
                }
 
1541
        }
 
1542
 
 
1543
        if ( rc == -1 ) {
 
1544
                /*
 
1545
                 * FIXME: need a better strategy to handle errors
 
1546
                 */
 
1547
                if ( mc ) {
 
1548
                        rc = meta_back_op_result( mc, op, rs, META_TARGET_NONE,
 
1549
                                -1, stoptime != -1 ? (stoptime - slap_get_time()) : 0,
 
1550
                                LDAP_BACK_SENDERR );
 
1551
                } else {
 
1552
                        rc = rs->sr_err;
 
1553
                }
 
1554
                goto finish;
 
1555
        }
 
1556
 
 
1557
        /*
 
1558
         * Rewrite the matched portion of the search base, if required
 
1559
         * 
 
1560
         * FIXME: only the last one gets caught!
 
1561
         */
 
1562
        savepriv = op->o_private;
 
1563
        op->o_private = (void *)(long)mi->mi_ntargets;
 
1564
        if ( candidate_match > 0 ) {
 
1565
                struct berval   pmatched = BER_BVNULL;
 
1566
 
 
1567
                /* we use the first one */
 
1568
                for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
1569
                        if ( META_IS_CANDIDATE( &candidates[ i ] )
 
1570
                                        && candidates[ i ].sr_matched != NULL )
 
1571
                        {
 
1572
                                struct berval   bv, pbv;
 
1573
                                int             rc;
 
1574
 
 
1575
                                /* if we got success, and this target
 
1576
                                 * returned noSuchObject, and its suffix
 
1577
                                 * is a superior of the searchBase,
 
1578
                                 * ignore the matchedDN */
 
1579
                                if ( sres == LDAP_SUCCESS
 
1580
                                        && candidates[ i ].sr_err == LDAP_NO_SUCH_OBJECT
 
1581
                                        && op->o_req_ndn.bv_len > mi->mi_targets[ i ]->mt_nsuffix.bv_len )
 
1582
                                {
 
1583
                                        free( (char *)candidates[ i ].sr_matched );
 
1584
                                        candidates[ i ].sr_matched = NULL;
 
1585
                                        continue;
 
1586
                                }
 
1587
 
 
1588
                                ber_str2bv( candidates[ i ].sr_matched, 0, 0, &bv );
 
1589
                                rc = dnPretty( NULL, &bv, &pbv, op->o_tmpmemctx );
 
1590
 
 
1591
                                if ( rc == LDAP_SUCCESS ) {
 
1592
 
 
1593
                                        /* NOTE: if they all are superiors
 
1594
                                         * of the baseDN, the shorter is also 
 
1595
                                         * superior of the longer... */
 
1596
                                        if ( pbv.bv_len > pmatched.bv_len ) {
 
1597
                                                if ( !BER_BVISNULL( &pmatched ) ) {
 
1598
                                                        op->o_tmpfree( pmatched.bv_val, op->o_tmpmemctx );
 
1599
                                                }
 
1600
                                                pmatched = pbv;
 
1601
                                                op->o_private = (void *)i;
 
1602
 
 
1603
                                        } else {
 
1604
                                                op->o_tmpfree( pbv.bv_val, op->o_tmpmemctx );
 
1605
                                        }
 
1606
                                }
 
1607
 
 
1608
                                if ( candidates[ i ].sr_matched != NULL ) {
 
1609
                                        free( (char *)candidates[ i ].sr_matched );
 
1610
                                        candidates[ i ].sr_matched = NULL;
 
1611
                                }
 
1612
                        }
 
1613
                }
 
1614
 
 
1615
                if ( !BER_BVISNULL( &pmatched ) ) {
 
1616
                        matched = pmatched.bv_val;
 
1617
                }
 
1618
 
 
1619
        } else if ( sres == LDAP_NO_SUCH_OBJECT ) {
 
1620
                matched = op->o_bd->be_suffix[ 0 ].bv_val;
 
1621
        }
 
1622
 
 
1623
        /*
 
1624
         * In case we returned at least one entry, we return LDAP_SUCCESS
 
1625
         * otherwise, the latter error code we got
 
1626
         */
 
1627
 
 
1628
        if ( sres == LDAP_SUCCESS ) {
 
1629
                if ( rs->sr_v2ref ) {
 
1630
                        sres = LDAP_REFERRAL;
 
1631
                }
 
1632
 
 
1633
                if ( META_BACK_ONERR_REPORT( mi ) ) {
 
1634
                        /*
 
1635
                         * Report errors, if any
 
1636
                         *
 
1637
                         * FIXME: we should handle error codes and return the more 
 
1638
                         * important/reasonable
 
1639
                         */
 
1640
                        for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
1641
                                if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
 
1642
                                        continue;
 
1643
                                }
 
1644
 
 
1645
                                if ( candidates[ i ].sr_err != LDAP_SUCCESS
 
1646
                                        && candidates[ i ].sr_err != LDAP_NO_SUCH_OBJECT )
 
1647
                                {
 
1648
                                        sres = candidates[ i ].sr_err;
 
1649
                                        break;
 
1650
                                }
 
1651
                        }
 
1652
                }
 
1653
        }
 
1654
 
 
1655
        rs->sr_err = sres;
 
1656
        rs->sr_matched = matched;
 
1657
        rs->sr_ref = ( sres == LDAP_REFERRAL ? rs->sr_v2ref : NULL );
 
1658
        send_ldap_result( op, rs );
 
1659
        op->o_private = savepriv;
 
1660
        rs->sr_matched = NULL;
 
1661
        rs->sr_ref = NULL;
 
1662
 
 
1663
finish:;
 
1664
        if ( matched && matched != op->o_bd->be_suffix[ 0 ].bv_val ) {
 
1665
                op->o_tmpfree( matched, op->o_tmpmemctx );
 
1666
        }
 
1667
 
 
1668
        if ( rs->sr_v2ref ) {
 
1669
                ber_bvarray_free( rs->sr_v2ref );
 
1670
        }
 
1671
 
 
1672
        for ( i = 0; i < mi->mi_ntargets; i++ ) {
 
1673
                if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
 
1674
                        continue;
 
1675
                }
 
1676
 
 
1677
                if ( mc ) {
 
1678
                        if ( META_IS_BINDING( &candidates[ i ] )
 
1679
                                || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
 
1680
                        {
 
1681
                                ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
 
1682
                                if ( LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] )
 
1683
                                        || candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
 
1684
                                {
 
1685
                                        assert( candidates[ i ].sr_msgid >= 0
 
1686
                                                || candidates[ i ].sr_msgid == META_MSGID_CONNECTING );
 
1687
                                        assert( mc->mc_conns[ i ].msc_ld != NULL );
 
1688
 
 
1689
#ifdef DEBUG_205
 
1690
                                        Debug( LDAP_DEBUG_ANY, "### %s meta_back_search(cleanup) "
 
1691
                                                "ldap_unbind_ext[%ld] ld=%p\n",
 
1692
                                                op->o_log_prefix, i, (void *)mc->mc_conns[i].msc_ld );
 
1693
#endif /* DEBUG_205 */
 
1694
 
 
1695
                                        /* if still binding, destroy */
 
1696
                                        meta_clear_one_candidate( op, mc, i );
 
1697
                                }
 
1698
                                ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
 
1699
                                META_BINDING_CLEAR( &candidates[ i ] );
 
1700
 
 
1701
                        } else if ( candidates[ i ].sr_msgid >= 0 ) {
 
1702
                                (void)meta_back_cancel( mc, op, rs,
 
1703
                                        candidates[ i ].sr_msgid, i,
 
1704
                                        LDAP_BACK_DONTSEND );
 
1705
                        }
 
1706
                }
 
1707
 
 
1708
                if ( candidates[ i ].sr_matched ) {
 
1709
                        free( (char *)candidates[ i ].sr_matched );
 
1710
                        candidates[ i ].sr_matched = NULL;
 
1711
                }
 
1712
 
 
1713
                if ( candidates[ i ].sr_text ) {
 
1714
                        ldap_memfree( (char *)candidates[ i ].sr_text );
 
1715
                        candidates[ i ].sr_text = NULL;
 
1716
                }
 
1717
 
 
1718
                if ( candidates[ i ].sr_ref ) {
 
1719
                        ber_bvarray_free( candidates[ i ].sr_ref );
 
1720
                        candidates[ i ].sr_ref = NULL;
 
1721
                }
 
1722
 
 
1723
                if ( candidates[ i ].sr_ctrls ) {
 
1724
                        ldap_controls_free( candidates[ i ].sr_ctrls );
 
1725
                        candidates[ i ].sr_ctrls = NULL;
 
1726
                }
 
1727
 
 
1728
                if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
 
1729
                        meta_back_quarantine( op, &candidates[ i ], i );
 
1730
                }
 
1731
 
 
1732
                /* only in case of timelimit exceeded, if the timelimit exceeded because
 
1733
                 * one contacted target never responded, invalidate the connection
 
1734
                 * NOTE: should we quarantine the target as well?  right now, the connection
 
1735
                 * is invalidated; the next time it will be recreated and the target
 
1736
                 * will be quarantined if it cannot be contacted */
 
1737
                if ( mi->mi_idle_timeout != 0
 
1738
                        && rs->sr_err == LDAP_TIMELIMIT_EXCEEDED
 
1739
                        && op->o_time > mc->mc_conns[ i ].msc_time )
 
1740
                {
 
1741
                        /* don't let anyone else use this expired connection */
 
1742
                        LDAP_BACK_CONN_TAINTED_SET( mc );
 
1743
                }
 
1744
        }
 
1745
 
 
1746
        if ( mc ) {
 
1747
                meta_back_release_conn( mi, mc );
 
1748
        }
 
1749
 
 
1750
        return rs->sr_err;
 
1751
}
 
1752
 
 
1753
static int
 
1754
meta_send_entry(
 
1755
        Operation       *op,
 
1756
        SlapReply       *rs,
 
1757
        metaconn_t      *mc,
 
1758
        int             target,
 
1759
        LDAPMessage     *e )
 
1760
{
 
1761
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
 
1762
        struct berval           a, mapped;
 
1763
        int                     check_duplicate_attrs = 0;
 
1764
        Entry                   ent = { 0 };
 
1765
        BerElement              ber = *e->lm_ber;
 
1766
        Attribute               *attr, **attrp;
 
1767
        struct berval           bdn,
 
1768
                                dn = BER_BVNULL;
 
1769
        const char              *text;
 
1770
        dncookie                dc;
 
1771
        int                     rc;
 
1772
 
 
1773
        if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
 
1774
                return LDAP_DECODING_ERROR;
 
1775
        }
 
1776
 
 
1777
        /*
 
1778
         * Rewrite the dn of the result, if needed
 
1779
         */
 
1780
        dc.target = mi->mi_targets[ target ];
 
1781
        dc.conn = op->o_conn;
 
1782
        dc.rs = rs;
 
1783
        dc.ctx = "searchResult";
 
1784
 
 
1785
        rs->sr_err = ldap_back_dn_massage( &dc, &bdn, &dn );
 
1786
        if ( rs->sr_err != LDAP_SUCCESS) {
 
1787
                return rs->sr_err;
 
1788
        }
 
1789
 
 
1790
        /*
 
1791
         * Note: this may fail if the target host(s) schema differs
 
1792
         * from the one known to the meta, and a DN with unknown
 
1793
         * attributes is returned.
 
1794
         * 
 
1795
         * FIXME: should we log anything, or delegate to dnNormalize?
 
1796
         */
 
1797
        rc = dnPrettyNormal( NULL, &dn, &ent.e_name, &ent.e_nname,
 
1798
                op->o_tmpmemctx );
 
1799
        if ( dn.bv_val != bdn.bv_val ) {
 
1800
                free( dn.bv_val );
 
1801
        }
 
1802
        BER_BVZERO( &dn );
 
1803
 
 
1804
        if ( rc != LDAP_SUCCESS ) {
 
1805
                return LDAP_INVALID_DN_SYNTAX;
 
1806
        }
 
1807
 
 
1808
        /*
 
1809
         * cache dn
 
1810
         */
 
1811
        if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED ) {
 
1812
                ( void )meta_dncache_update_entry( &mi->mi_cache,
 
1813
                                &ent.e_nname, target );
 
1814
        }
 
1815
 
 
1816
        attrp = &ent.e_attrs;
 
1817
 
 
1818
        dc.ctx = "searchAttrDN";
 
1819
        while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
 
1820
                int                             last = 0;
 
1821
                slap_syntax_validate_func       *validate;
 
1822
                slap_syntax_transform_func      *pretty;
 
1823
 
 
1824
                ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_at, 
 
1825
                                &a, &mapped, BACKLDAP_REMAP );
 
1826
                if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
 
1827
                        ( void )ber_scanf( &ber, "x" /* [W] */ );
 
1828
                        continue;
 
1829
                }
 
1830
                if ( mapped.bv_val != a.bv_val ) {
 
1831
                        /* will need to check for duplicate attrs */
 
1832
                        check_duplicate_attrs++;
 
1833
                }
 
1834
                attr = attr_alloc( NULL );
 
1835
                if ( attr == NULL ) {
 
1836
                        continue;
 
1837
                }
 
1838
                if ( slap_bv2ad( &mapped, &attr->a_desc, &text )
 
1839
                                != LDAP_SUCCESS) {
 
1840
                        if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text,
 
1841
                                SLAP_AD_PROXIED ) != LDAP_SUCCESS )
 
1842
                        {
 
1843
                                char    buf[ SLAP_TEXT_BUFLEN ];
 
1844
 
 
1845
                                snprintf( buf, sizeof( buf ),
 
1846
                                        "%s meta_send_entry(\"%s\"): "
 
1847
                                        "slap_bv2undef_ad(%s): %s\n",
 
1848
                                        op->o_log_prefix, ent.e_name.bv_val,
 
1849
                                        mapped.bv_val, text );
 
1850
 
 
1851
                                Debug( LDAP_DEBUG_ANY, "%s", buf, 0, 0 );
 
1852
                                attr_free( attr );
 
1853
                                continue;
 
1854
                        }
 
1855
                }
 
1856
 
 
1857
                /* no subschemaSubentry */
 
1858
                if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry
 
1859
                        || attr->a_desc == slap_schema.si_ad_entryDN )
 
1860
                {
 
1861
 
 
1862
                        /* 
 
1863
                         * We eat target's subschemaSubentry because
 
1864
                         * a search for this value is likely not
 
1865
                         * to resolve to the appropriate backend;
 
1866
                         * later, the local subschemaSubentry is
 
1867
                         * added.
 
1868
                         *
 
1869
                         * We also eat entryDN because the frontend
 
1870
                         * will reattach it without checking if already
 
1871
                         * present...
 
1872
                         */
 
1873
                        ( void )ber_scanf( &ber, "x" /* [W] */ );
 
1874
 
 
1875
                        attr_free(attr);
 
1876
                        continue;
 
1877
                }
 
1878
 
 
1879
                if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
 
1880
                                || attr->a_vals == NULL )
 
1881
                {
 
1882
                        attr->a_vals = (struct berval *)&slap_dummy_bv;
 
1883
 
 
1884
                } else {
 
1885
                        for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); ++last )
 
1886
                                ;
 
1887
                }
 
1888
                attr->a_numvals = last;
 
1889
 
 
1890
                validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate;
 
1891
                pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty;
 
1892
 
 
1893
                if ( !validate && !pretty ) {
 
1894
                        attr_free( attr );
 
1895
                        goto next_attr;
 
1896
                }
 
1897
 
 
1898
                if ( attr->a_desc == slap_schema.si_ad_objectClass
 
1899
                                || attr->a_desc == slap_schema.si_ad_structuralObjectClass )
 
1900
                {
 
1901
                        struct berval   *bv;
 
1902
 
 
1903
                        for ( bv = attr->a_vals; !BER_BVISNULL( bv ); bv++ ) {
 
1904
                                ldap_back_map( &mi->mi_targets[ target ]->mt_rwmap.rwm_oc,
 
1905
                                                bv, &mapped, BACKLDAP_REMAP );
 
1906
                                if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0') {
 
1907
remove_oc:;
 
1908
                                        free( bv->bv_val );
 
1909
                                        BER_BVZERO( bv );
 
1910
                                        if ( --last < 0 ) {
 
1911
                                                break;
 
1912
                                        }
 
1913
                                        *bv = attr->a_vals[ last ];
 
1914
                                        BER_BVZERO( &attr->a_vals[ last ] );
 
1915
                                        bv--;
 
1916
 
 
1917
                                } else if ( mapped.bv_val != bv->bv_val ) {
 
1918
                                        int     i;
 
1919
 
 
1920
                                        for ( i = 0; !BER_BVISNULL( &attr->a_vals[ i ] ); i++ ) {
 
1921
                                                if ( &attr->a_vals[ i ] == bv ) {
 
1922
                                                        continue;
 
1923
                                                }
 
1924
 
 
1925
                                                if ( ber_bvstrcasecmp( &mapped, &attr->a_vals[ i ] ) == 0 ) {
 
1926
                                                        break;
 
1927
                                                }
 
1928
                                        }
 
1929
 
 
1930
                                        if ( !BER_BVISNULL( &attr->a_vals[ i ] ) ) {
 
1931
                                                goto remove_oc;
 
1932
                                        }
 
1933
 
 
1934
                                        ber_bvreplace( bv, &mapped );
 
1935
                                }
 
1936
                        }
 
1937
                /*
 
1938
                 * It is necessary to try to rewrite attributes with
 
1939
                 * dn syntax because they might be used in ACLs as
 
1940
                 * members of groups; since ACLs are applied to the
 
1941
                 * rewritten stuff, no dn-based subecj clause could
 
1942
                 * be used at the ldap backend side (see
 
1943
                 * http://www.OpenLDAP.org/faq/data/cache/452.html)
 
1944
                 * The problem can be overcome by moving the dn-based
 
1945
                 * ACLs to the target directory server, and letting
 
1946
                 * everything pass thru the ldap backend.
 
1947
                 */
 
1948
                } else {
 
1949
                        int     i;
 
1950
 
 
1951
                        if ( attr->a_desc->ad_type->sat_syntax ==
 
1952
                                slap_schema.si_syn_distinguishedName )
 
1953
                        {
 
1954
                                ldap_dnattr_result_rewrite( &dc, attr->a_vals );
 
1955
 
 
1956
                        } else if ( attr->a_desc == slap_schema.si_ad_ref ) {
 
1957
                                ldap_back_referral_result_rewrite( &dc, attr->a_vals );
 
1958
 
 
1959
                        }
 
1960
 
 
1961
                        for ( i = 0; i < last; i++ ) {
 
1962
                                struct berval   pval;
 
1963
                                int             rc;
 
1964
 
 
1965
                                if ( pretty ) {
 
1966
                                        rc = pretty( attr->a_desc->ad_type->sat_syntax,
 
1967
                                                &attr->a_vals[i], &pval, NULL );
 
1968
 
 
1969
                                } else {
 
1970
                                        rc = validate( attr->a_desc->ad_type->sat_syntax,
 
1971
                                                &attr->a_vals[i] );
 
1972
                                }
 
1973
 
 
1974
                                if ( rc ) {
 
1975
                                        LBER_FREE( attr->a_vals[i].bv_val );
 
1976
                                        if ( --last == i ) {
 
1977
                                                BER_BVZERO( &attr->a_vals[ i ] );
 
1978
                                                break;
 
1979
                                        }
 
1980
                                        attr->a_vals[i] = attr->a_vals[last];
 
1981
                                        BER_BVZERO( &attr->a_vals[last] );
 
1982
                                        i--;
 
1983
                                        continue;
 
1984
                                }
 
1985
 
 
1986
                                if ( pretty ) {
 
1987
                                        LBER_FREE( attr->a_vals[i].bv_val );
 
1988
                                        attr->a_vals[i] = pval;
 
1989
                                }
 
1990
                        }
 
1991
 
 
1992
                        if ( last == 0 && attr->a_vals != &slap_dummy_bv ) {
 
1993
                                attr_free( attr );
 
1994
                                goto next_attr;
 
1995
                        }
 
1996
                }
 
1997
 
 
1998
                if ( last && attr->a_desc->ad_type->sat_equality &&
 
1999
                        attr->a_desc->ad_type->sat_equality->smr_normalize )
 
2000
                {
 
2001
                        int i;
 
2002
 
 
2003
                        attr->a_nvals = ch_malloc( ( last + 1 ) * sizeof( struct berval ) );
 
2004
                        for ( i = 0; i<last; i++ ) {
 
2005
                                attr->a_desc->ad_type->sat_equality->smr_normalize(
 
2006
                                        SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
 
2007
                                        attr->a_desc->ad_type->sat_syntax,
 
2008
                                        attr->a_desc->ad_type->sat_equality,
 
2009
                                        &attr->a_vals[i], &attr->a_nvals[i],
 
2010
                                        NULL );
 
2011
                        }
 
2012
                        BER_BVZERO( &attr->a_nvals[i] );
 
2013
 
 
2014
                } else {
 
2015
                        attr->a_nvals = attr->a_vals;
 
2016
                }
 
2017
 
 
2018
                *attrp = attr;
 
2019
                attrp = &attr->a_next;
 
2020
next_attr:;
 
2021
        }
 
2022
 
 
2023
        /* only check if some mapping occurred */
 
2024
        if ( check_duplicate_attrs ) {
 
2025
                Attribute       **ap;
 
2026
 
 
2027
                for ( ap = &ent.e_attrs; *ap != NULL; ap = &(*ap)->a_next ) {
 
2028
                        Attribute       **tap;
 
2029
 
 
2030
                        for ( tap = &(*ap)->a_next; *tap != NULL; ) {
 
2031
                                if ( (*tap)->a_desc == (*ap)->a_desc ) {
 
2032
                                        Entry           e = { 0 };
 
2033
                                        Modification    mod = { 0 };
 
2034
                                        const char      *text = NULL;
 
2035
                                        char            textbuf[ SLAP_TEXT_BUFLEN ];
 
2036
                                        Attribute       *next = (*tap)->a_next;
 
2037
 
 
2038
                                        BER_BVSTR( &e.e_name, "" );
 
2039
                                        BER_BVSTR( &e.e_nname, "" );
 
2040
                                        e.e_attrs = *ap;
 
2041
                                        mod.sm_op = LDAP_MOD_ADD;
 
2042
                                        mod.sm_desc = (*ap)->a_desc;
 
2043
                                        mod.sm_type = mod.sm_desc->ad_cname;
 
2044
                                        mod.sm_numvals = (*ap)->a_numvals;
 
2045
                                        mod.sm_values = (*tap)->a_vals;
 
2046
                                        if ( (*tap)->a_nvals != (*tap)->a_vals ) {
 
2047
                                                mod.sm_nvalues = (*tap)->a_nvals;
 
2048
                                        }
 
2049
 
 
2050
                                        (void)modify_add_values( &e, &mod,
 
2051
                                                /* permissive */ 1,
 
2052
                                                &text, textbuf, sizeof( textbuf ) );
 
2053
 
 
2054
                                        /* should not insert new attrs! */
 
2055
                                        assert( e.e_attrs == *ap );
 
2056
 
 
2057
                                        attr_free( *tap );
 
2058
                                        *tap = next;
 
2059
 
 
2060
                                } else {
 
2061
                                        tap = &(*tap)->a_next;
 
2062
                                }
 
2063
                        }
 
2064
                }
 
2065
        }
 
2066
 
 
2067
        ldap_get_entry_controls( mc->mc_conns[target].msc_ld,
 
2068
                e, &rs->sr_ctrls );
 
2069
        rs->sr_entry = &ent;
 
2070
        rs->sr_attrs = op->ors_attrs;
 
2071
        rs->sr_operational_attrs = NULL;
 
2072
        rs->sr_flags = 0;
 
2073
        rs->sr_err = LDAP_SUCCESS;
 
2074
        rc = send_search_entry( op, rs );
 
2075
        switch ( rc ) {
 
2076
        case LDAP_UNAVAILABLE:
 
2077
                rc = LDAP_OTHER;
 
2078
                break;
 
2079
        }
 
2080
        rs->sr_entry = NULL;
 
2081
        rs->sr_attrs = NULL;
 
2082
        if ( rs->sr_ctrls != NULL ) {
 
2083
                ldap_controls_free( rs->sr_ctrls );
 
2084
                rs->sr_ctrls = NULL;
 
2085
        }
 
2086
        if ( !BER_BVISNULL( &ent.e_name ) ) {
 
2087
                free( ent.e_name.bv_val );
 
2088
                BER_BVZERO( &ent.e_name );
 
2089
        }
 
2090
        if ( !BER_BVISNULL( &ent.e_nname ) ) {
 
2091
                free( ent.e_nname.bv_val );
 
2092
                BER_BVZERO( &ent.e_nname );
 
2093
        }
 
2094
        entry_clean( &ent );
 
2095
 
 
2096
        return rc;
 
2097
}
 
2098