upstream.c 32.1 KB
Newer Older
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
 * Copyright 1998-2020 The OpenLDAP Foundation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */

#include "portable.h"

#include <ac/socket.h>
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>

24
#include "lload.h"
Ondřej Kuzník's avatar
Ondřej Kuzník committed
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "lutil.h"
#include "lutil_ldap.h"

#ifdef HAVE_CYRUS_SASL
static const sasl_callback_t client_callbacks[] = {
#ifdef SASL_CB_GETREALM
        { SASL_CB_GETREALM, NULL, NULL },
#endif
        { SASL_CB_USER, NULL, NULL },
        { SASL_CB_AUTHNAME, NULL, NULL },
        { SASL_CB_PASS, NULL, NULL },
        { SASL_CB_LIST_END, NULL, NULL }
};
#endif /* HAVE_CYRUS_SASL */

41
42
static void upstream_unlink( LloadConnection *upstream );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
43
int
44
forward_response( LloadConnection *client, LloadOperation *op, BerElement *ber )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
45
46
47
{
    BerElement *output;
    BerValue response, controls = BER_BVNULL;
48
    ber_int_t msgid;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
49
50
51
    ber_tag_t tag, response_tag;
    ber_len_t len;

52
53
54
55
56
57
58
59
60
61
    CONNECTION_LOCK(client);
    if ( op->o_client_msgid ) {
        msgid = op->o_client_msgid;
    } else {
        assert( op->o_pin_id );
        msgid = op->o_saved_msgid;
        op->o_saved_msgid = 0;
    }
    CONNECTION_UNLOCK(client);

Ondřej Kuzník's avatar
Ondřej Kuzník committed
62
63
64
65
66
67
68
    response_tag = ber_skip_element( ber, &response );

    tag = ber_peek_tag( ber, &len );
    if ( tag == LDAP_TAG_CONTROLS ) {
        ber_skip_element( ber, &controls );
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
69
    Debug( LDAP_DEBUG_TRACE, "forward_response: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
70
            "%s to client connid=%lu request msgid=%d\n",
71
            lload_msgtype2str( response_tag ), op->o_client_connid, msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
72

73
74
    ldap_pvt_thread_mutex_lock( &client->c_io_mutex );
    output = client->c_pendingber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
75
76
    if ( output == NULL && (output = ber_alloc()) == NULL ) {
        ber_free( ber, 1 );
77
        ldap_pvt_thread_mutex_unlock( &client->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
78
79
        return -1;
    }
80
    client->c_pendingber = output;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
81
82

    ber_printf( output, "t{titOtO}", LDAP_TAG_MESSAGE,
83
            LDAP_TAG_MSGID, msgid,
Ondřej Kuzník's avatar
Ondřej Kuzník committed
84
85
86
            response_tag, &response,
            LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &controls ) );

87
    ldap_pvt_thread_mutex_unlock( &client->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
88
89

    ber_free( ber, 1 );
90
    connection_write_cb( -1, 0, client );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
91
92
93
    return 0;
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
94
int
95
96
97
98
forward_final_response(
        LloadConnection *client,
        LloadOperation *op,
        BerElement *ber )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
99
100
101
{
    int rc;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
102
    Debug( LDAP_DEBUG_STATS, "forward_final_response: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
103
104
105
            "connid=%lu msgid=%d finishing up with a request for "
            "client connid=%lu\n",
            op->o_upstream_connid, op->o_upstream_msgid, op->o_client_connid );
106

107
    rc = forward_response( client, op, ber );
108

109
    op->o_res = LLOAD_OP_COMPLETED;
110
111
    if ( !op->o_pin_id ) {
        operation_unlink( op );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
112
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
113
114
115
116
117

    return rc;
}

static int
118
handle_unsolicited( LloadConnection *c, BerElement *ber )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
119
{
120
    if ( c->c_state != LLOAD_C_PREPARING ) {
121
        c->c_state = LLOAD_C_CLOSING;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
122
    }
123

124
    Debug( LDAP_DEBUG_STATS, "handle_unsolicited: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
125
            "teardown for upstream connection connid=%lu\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
126
127
            c->c_connid );

128
    CONNECTION_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    ber_free( ber, 1 );

    return -1;
}

/*
 * Pull c->c_currentber from the connection and try to look up the operation on
 * the upstream.
 *
 * If it's a notice of disconnection, we won't find it and need to tear down
 * the connection and tell the clients, if we can't find the operation, ignore
 * the message (either client already disconnected/abandoned it or the upstream
 * is pulling our leg).
 *
 * Some responses need special handling:
 * - Bind response
 * - VC response where the client requested a Bind (both need to update the
 *   client's bind status)
 * - search entries/referrals and intermediate responses (will not trigger
 *   operation to be removed)
 *
 * If the worker pool is overloaded, we might be called directly from
151
 * the read callback, at that point, the connection hasn't been muted.
Ondřej Kuzník's avatar
Ondřej Kuzník committed
152
153
154
155
 *
 * TODO: when the client already has data pending on write, we should mute the
 * upstream.
 * - should record the BerElement on the Op and the Op on the client
Ondřej Kuzník's avatar
Ondřej Kuzník committed
156
157
158
159
160
 *
 * The following hold on entering any of the handlers:
 * - op->o_upstream_refcnt > 0
 * - op->o_upstream->c_refcnt > 0
 * - op->o_client->c_refcnt > 0
Ondřej Kuzník's avatar
Ondřej Kuzník committed
161
162
 */
static int
163
handle_one_response( LloadConnection *c )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
164
165
{
    BerElement *ber;
166
167
    LloadOperation *op = NULL, needle = { .o_upstream_connid = c->c_connid };
    LloadOperationHandler handler = NULL;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
168
169
    ber_tag_t tag;
    ber_len_t len;
170
    int rc = LDAP_SUCCESS;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
171
172
173
174
175
176
177
178
179
180
181

    ber = c->c_currentber;
    c->c_currentber = NULL;

    tag = ber_get_int( ber, &needle.o_upstream_msgid );
    if ( tag != LDAP_TAG_MSGID ) {
        rc = -1;
        ber_free( ber, 1 );
        goto fail;
    }

182
    CONNECTION_LOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
183
184
185
186
187
    if ( needle.o_upstream_msgid == 0 ) {
        return handle_unsolicited( c, ber );
    } else if ( !( op = tavl_find(
                           c->c_ops, &needle, operation_upstream_cmp ) ) ) {
        /* Already abandoned, do nothing */
188
        CONNECTION_UNLOCK(c);
189
190
        ber_free( ber, 1 );
        return rc;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
191
192
193
194
195
196
        /*
    } else if ( op->o_response_pending ) {
        c->c_pendingop = op;
        event_del( c->c_read_event );
    */
    } else {
197
        CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
        /*
        op->o_response_pending = ber;
        */

        tag = ber_peek_tag( ber, &len );
        switch ( tag ) {
            case LDAP_RES_SEARCH_ENTRY:
            case LDAP_RES_SEARCH_REFERENCE:
            case LDAP_RES_INTERMEDIATE:
                handler = forward_response;
                break;
            case LDAP_RES_BIND:
                handler = handle_bind_response;
                break;
            case LDAP_RES_EXTENDED:
                if ( op->o_tag == LDAP_REQ_BIND ) {
214
215
216
217
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
                    if ( lload_features & LLOAD_FEATURE_VC ) {
                        handler = handle_vc_bind_response;
                    } else
218
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
219
220
221
222
                    {
                        handler = handle_whoami_response;
                    }
                }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
223
224
225
226
227
228
229
                break;
        }
        if ( !handler ) {
            handler = forward_final_response;
        }
    }
    if ( op ) {
230
        op->o_last_response = slap_get_time();
Ondřej Kuzník's avatar
Ondřej Kuzník committed
231
        Debug( LDAP_DEBUG_STATS2, "handle_one_response: "
Ondřej Kuzník's avatar
Ondřej Kuzník committed
232
233
                "upstream connid=%lu, processing response for "
                "client connid=%lu, msgid=%d\n",
234
                c->c_connid, op->o_client_connid, op->o_client_msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
235
236
    } else {
        tag = ber_peek_tag( ber, &len );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
237
238
239
        Debug( LDAP_DEBUG_STATS2, "handle_one_response: "
                "upstream connid=%lu, %s, msgid=%d not for a pending "
                "operation\n",
240
241
                c->c_connid, lload_msgtype2str( tag ),
                needle.o_upstream_msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
242
243
244
    }

    if ( handler ) {
245
        LloadConnection *client;
246

Ondřej Kuzník's avatar
Ondřej Kuzník committed
247
        ldap_pvt_thread_mutex_lock( &op->o_link_mutex );
248
        client = op->o_client;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
249
        ldap_pvt_thread_mutex_unlock( &op->o_link_mutex );
250
        if ( client && IS_ALIVE( client, c_live ) ) {
251
            rc = handler( client, op, ber );
252
253
254
255
        } else {
            ber_free( ber, 1 );
        }
    } else {
256
        assert(0);
257
        ber_free( ber, 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
258
259
260
261
    }

fail:
    if ( rc ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
262
263
264
        Debug( LDAP_DEBUG_STATS, "handle_one_response: "
                "error on processing a response (%s) on upstream connection "
                "connid=%ld, tag=%lx\n",
265
                lload_msgtype2str( tag ), c->c_connid, tag );
266
        CONNECTION_LOCK_DESTROY(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
267
268
269
270
    }
    return rc;
}

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
#ifdef HAVE_CYRUS_SASL
static int
sasl_bind_step( LloadConnection *c, BerValue *scred, BerValue *ccred )
{
    LloadBackend *b = c->c_private;
    sasl_conn_t *ctx = c->c_sasl_authctx;
    sasl_interact_t *prompts = NULL;
    unsigned credlen;
    int rc = -1;

    if ( !ctx ) {
        const char *mech = NULL;
        void *ssl;

        if ( sasl_client_new( "ldap", b->b_host, NULL, NULL, client_callbacks,
                     0, &ctx ) != SASL_OK ) {
            goto done;
        }
        c->c_sasl_authctx = ctx;

        assert( c->c_sasl_defaults == NULL );
        c->c_sasl_defaults =
                lutil_sasl_defaults( NULL, bindconf.sb_saslmech.bv_val,
                        bindconf.sb_realm.bv_val, bindconf.sb_authcId.bv_val,
                        bindconf.sb_cred.bv_val, bindconf.sb_authzId.bv_val );

#ifdef HAVE_TLS
        /* Check for TLS */
        ssl = ldap_pvt_tls_sb_ctx( c->c_sb );
        if ( ssl ) {
            struct berval authid = BER_BVNULL;
            ber_len_t ssf;

            ssf = ldap_pvt_tls_get_strength( ssl );
            (void)ldap_pvt_tls_get_my_dn( ssl, &authid, NULL, 0 );

            sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf );
            sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid.bv_val );
            ch_free( authid.bv_val );
#ifdef SASL_CHANNEL_BINDING /* 2.1.25+ */
            {
                char cbinding[64];
                struct berval cbv = { sizeof(cbinding), cbinding };
                if ( ldap_pvt_tls_get_unique( ssl, &cbv, 0 ) ) {
                    sasl_channel_binding_t *cb =
                            ch_malloc( sizeof(*cb) + cbv.bv_len );
                    void *cb_data;
                    cb->name = "ldap";
                    cb->critical = 0;
                    cb->len = cbv.bv_len;
                    cb->data = cb_data = cb + 1;
                    memcpy( cb_data, cbv.bv_val, cbv.bv_len );
                    sasl_setprop( ctx, SASL_CHANNEL_BINDING, cb );
324
                    c->c_sasl_cbinding = cb;
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
                }
            }
#endif
        }
#endif

#if !defined(_WIN32)
        /* Check for local */
        if ( b->b_proto == LDAP_PROTO_IPC ) {
            char authid[sizeof( "gidNumber=4294967295+uidNumber=4294967295,"
                                "cn=peercred,cn=external,cn=auth" )];
            int ssf = LDAP_PVT_SASL_LOCAL_SSF;

            sprintf( authid,
                    "gidNumber=%u+uidNumber=%u,"
                    "cn=peercred,cn=external,cn=auth",
                    getegid(), geteuid() );
            sasl_setprop( ctx, SASL_SSF_EXTERNAL, &ssf );
            sasl_setprop( ctx, SASL_AUTH_EXTERNAL, authid );
        }
#endif

        do {
            rc = sasl_client_start( ctx, bindconf.sb_saslmech.bv_val,
                    &prompts,
                    (const char **)&ccred->bv_val, &credlen,
                    &mech );

            if ( rc == SASL_INTERACT ) {
                if ( lutil_sasl_interact( NULL, LDAP_SASL_QUIET,
                             c->c_sasl_defaults, prompts ) ) {
                    break;
                }
            }
        } while ( rc == SASL_INTERACT );

        ber_str2bv( mech, 0, 0, &c->c_sasl_bind_mech );
    } else {
        assert( c->c_sasl_defaults );

        do {
            rc = sasl_client_step( ctx,
                    (scred == NULL) ? NULL : scred->bv_val,
                    (scred == NULL) ? 0 : scred->bv_len,
                    &prompts,
                    (const char **)&ccred->bv_val, &credlen);

            if ( rc == SASL_INTERACT ) {
                if ( lutil_sasl_interact( NULL, LDAP_SASL_QUIET,
                             c->c_sasl_defaults, prompts ) ) {
                    break;
                }
            }
        } while ( rc == SASL_INTERACT );
    }

    if ( rc == SASL_OK ) {
        sasl_ssf_t *ssf;
        rc = sasl_getprop( ctx, SASL_SSF, (const void **)(char *)&ssf );
        if ( rc == SASL_OK && ssf && *ssf ) {
            Debug( LDAP_DEBUG_CONNS, "sasl_bind_step: "
                    "connid=%lu mech=%s setting up a new SASL security layer\n",
                    c->c_connid, c->c_sasl_bind_mech.bv_val );
            ldap_pvt_sasl_install( c->c_sb, ctx );
        }
    }
    ccred->bv_len = credlen;

done:
    Debug( LDAP_DEBUG_TRACE, "sasl_bind_step: "
            "connid=%lu next step for SASL bind mech=%s rc=%d\n",
            c->c_connid, c->c_sasl_bind_mech.bv_val, rc );
    return rc;
}
#endif /* HAVE_CYRUS_SASL */

401
int
402
upstream_bind_cb( LloadConnection *c )
403
{
Ondřej Kuzník's avatar
Ondřej Kuzník committed
404
    BerElement *ber = c->c_currentber;
405
    LloadBackend *b = c->c_private;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
406
    BerValue matcheddn, message;
407
408
409
410
411
412
    ber_tag_t tag;
    ber_int_t msgid, result;

    c->c_currentber = NULL;

    if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
413
414
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "protocol violation from server\n" );
415
416
417
418
        goto fail;
    }

    if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_BIND ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
419
420
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "unexpected %s from server, msgid=%d\n",
421
                lload_msgtype2str( tag ), msgid );
422
423
424
        goto fail;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
425
    if ( ber_scanf( ber, "{emm" /* "}" */, &result, &matcheddn, &message ) ==
426
                 LBER_ERROR ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
427
428
        Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                "response does not conform with a bind response\n" );
429
430
431
432
        goto fail;
    }

    switch ( result ) {
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
        case LDAP_SUCCESS:
#ifdef HAVE_CYRUS_SASL
        case LDAP_SASL_BIND_IN_PROGRESS:
            if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) {
                BerValue scred = BER_BVNULL, ccred;
                ber_len_t len;
                int rc;

                if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SASL_RES_CREDS &&
                        ber_scanf( ber, "m", &scred ) == LBER_ERROR ) {
                    Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                            "sasl bind response malformed\n" );
                    goto fail;
                }

                rc = sasl_bind_step( c, &scred, &ccred );
                if ( rc != SASL_OK &&
                        ( rc != SASL_CONTINUE || result == LDAP_SUCCESS ) ) {
                    goto fail;
                }

                if ( result == LDAP_SASL_BIND_IN_PROGRESS ) {
                    BerElement *outber;

                    ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
                    outber = c->c_pendingber;
                    if ( outber == NULL && (outber = ber_alloc()) == NULL ) {
                        ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
                        goto fail;
                    }
                    c->c_pendingber = outber;

                    msgid = c->c_next_msgid++;
                    ber_printf( outber, "{it{iOt{OON}N}}",
                            msgid, LDAP_REQ_BIND, LDAP_VERSION3,
                            &bindconf.sb_binddn, LDAP_AUTH_SASL,
                            &c->c_sasl_bind_mech, BER_BV_OPTIONAL( &ccred ) );
                    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );

                    connection_write_cb( -1, 0, c );

                    if ( rc == SASL_OK ) {
                        BER_BVZERO( &c->c_sasl_bind_mech );
                    }
                    break;
                }
            }
            if ( result == LDAP_SASL_BIND_IN_PROGRESS ) {
                goto fail;
            }
#endif /* HAVE_CYRUS_SASL */
484
            CONNECTION_LOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
485
            c->c_pdu_cb = handle_one_response;
486
487
            c->c_state = LLOAD_C_READY;
            c->c_type = LLOAD_C_OPEN;
488
489
490
491
            c->c_read_timeout = NULL;
            Debug( LDAP_DEBUG_CONNS, "upstream_bind_cb: "
                    "connid=%lu finished binding, now active\n",
                    c->c_connid );
492
            CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
493
494
495
496
497
            ldap_pvt_thread_mutex_lock( &b->b_mutex );
            LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next );
            b->b_active++;
            b->b_opening--;
            b->b_failed = 0;
498
499
500
501
502
503
504
            if ( b->b_last_conn ) {
                LDAP_CIRCLEQ_INSERT_AFTER(
                        &b->b_conns, b->b_last_conn, c, c_next );
            } else {
                LDAP_CIRCLEQ_INSERT_HEAD( &b->b_conns, c, c_next );
            }
            b->b_last_conn = c;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
505
            backend_retry( b );
506
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
507
            break;
508
509
510
        default:
            Debug( LDAP_DEBUG_ANY, "upstream_bind_cb: "
                    "upstream bind failed, rc=%d, message='%s'\n",
Ondřej Kuzník's avatar
Ondřej Kuzník committed
511
                    result, message.bv_val );
512
513
514
            goto fail;
    }

515
    event_add( c->c_read_event, c->c_read_timeout );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
516
    ber_free( ber, 1 );
517
    return -1;
518

Ondřej Kuzník's avatar
Ondřej Kuzník committed
519
fail:
520
    CONNECTION_LOCK_DESTROY(c);
521
    ber_free( ber, 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
522
    return -1;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
523
524
}

525
526
void *
upstream_bind( void *ctx, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
527
{
528
    LloadConnection *c = arg;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
529
    BerElement *ber;
530
    ber_int_t msgid;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
531

532
533
534
535
536
537
538
539
540
    /* A reference was passed on to us */
    assert( IS_ALIVE( c, c_refcnt ) );

    if ( !IS_ALIVE( c, c_live ) ) {
        RELEASE_REF( c, c_refcnt, c->c_destroy );
        return NULL;
    }

    CONNECTION_LOCK(c);
541
    assert( !event_pending( c->c_read_event, EV_READ, NULL ) );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
542
    c->c_pdu_cb = upstream_bind_cb;
543
    CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
544

Ondřej Kuzník's avatar
Ondřej Kuzník committed
545
546
547
    ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
    ber = c->c_pendingber;
    if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
548
        goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
549
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
550
    c->c_pendingber = ber;
551
552
    msgid = c->c_next_msgid++;

553
    if ( bindconf.sb_method == LDAP_AUTH_SIMPLE ) {
554
        /* simple bind */
555
        ber_printf( ber, "{it{iOtON}}",
556
                msgid, LDAP_REQ_BIND, LDAP_VERSION3,
557
558
                &bindconf.sb_binddn, LDAP_AUTH_SIMPLE,
                &bindconf.sb_cred );
559
560
561

#ifdef HAVE_CYRUS_SASL
    } else {
562
563
564
565
566
567
568
569
        BerValue cred;
        int rc;

        rc = sasl_bind_step( c, NULL, &cred );
        if ( rc != SASL_OK && rc != SASL_CONTINUE ) {
            goto fail;
        }

570
571
        ber_printf( ber, "{it{iOt{OON}N}}",
                msgid, LDAP_REQ_BIND, LDAP_VERSION3,
572
                &bindconf.sb_binddn, LDAP_AUTH_SASL,
573
574
575
576
577
                &c->c_sasl_bind_mech, BER_BV_OPTIONAL( &cred ) );

        if ( rc == SASL_OK ) {
            BER_BVZERO( &c->c_sasl_bind_mech );
        }
578
579
580
581
#endif /* HAVE_CYRUS_SASL */
    }
    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );

582
    connection_write_cb( -1, 0, c );
583

584
    CONNECTION_LOCK(c);
585
586
    c->c_read_timeout = lload_timeout_net;
    event_add( c->c_read_event, c->c_read_timeout );
587
    CONNECTION_UNLOCK(c);
588

589
    RELEASE_REF( c, c_refcnt, c->c_destroy );
590
    return NULL;
591
592
593
594

fail:
    ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
    CONNECTION_LOCK_DESTROY(c);
595
    RELEASE_REF( c, c_refcnt, c->c_destroy );
596
    return NULL;
597
598
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
599
600
601
602
/*
 * The backend is already locked when entering the function.
 */
static int
603
upstream_finish( LloadConnection *c )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
604
{
605
    LloadBackend *b = c->c_private;
606
    int is_bindconn = 0;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
607

608
    assert( c->c_live );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
    c->c_pdu_cb = handle_one_response;

    /* Unless we are configured to use the VC exop, consider allocating the
     * connection into the bind conn pool. Start off by allocating one for
     * general use, then one for binds, then we start filling up the general
     * connection pool, finally the bind pool */
    if (
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
            !(lload_features & LLOAD_FEATURE_VC) &&
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
            b->b_active && b->b_numbindconns ) {
        if ( !b->b_bindavail ) {
            is_bindconn = 1;
        } else if ( b->b_active >= b->b_numconns &&
                b->b_bindavail < b->b_numbindconns ) {
            is_bindconn = 1;
        }
    }

    if ( is_bindconn ) {
        LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next );
630
631
        c->c_state = LLOAD_C_READY;
        c->c_type = LLOAD_C_BIND;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
632
633
634
        b->b_bindavail++;
        b->b_opening--;
        b->b_failed = 0;
635
636
637
638
639
640
641
        if ( b->b_last_bindconn ) {
            LDAP_CIRCLEQ_INSERT_AFTER(
                    &b->b_bindconns, b->b_last_bindconn, c, c_next );
        } else {
            LDAP_CIRCLEQ_INSERT_HEAD( &b->b_bindconns, c, c_next );
        }
        b->b_last_bindconn = c;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
642
643
    } else if ( bindconf.sb_method == LDAP_AUTH_NONE ) {
        LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next );
644
645
        c->c_state = LLOAD_C_READY;
        c->c_type = LLOAD_C_OPEN;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
646
647
648
        b->b_active++;
        b->b_opening--;
        b->b_failed = 0;
649
650
651
652
653
654
        if ( b->b_last_conn ) {
            LDAP_CIRCLEQ_INSERT_AFTER( &b->b_conns, b->b_last_conn, c, c_next );
        } else {
            LDAP_CIRCLEQ_INSERT_HEAD( &b->b_conns, c, c_next );
        }
        b->b_last_conn = c;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
655
    } else {
656
657
658
659
660
661
662
        if ( ldap_pvt_thread_pool_submit(
                     &connection_pool, upstream_bind, c ) ) {
            Debug( LDAP_DEBUG_ANY, "upstream_finish: "
                    "failed to set up a bind callback for connid=%lu\n",
                    c->c_connid );
            return -1;
        }
663
664
        /* keep a reference for upstream_bind */
        acquire_ref( &c->c_refcnt );
665
666
667
668
669

        Debug( LDAP_DEBUG_CONNS, "upstream_finish: "
                "scheduled a bind callback for connid=%lu\n",
                c->c_connid );
        return LDAP_SUCCESS;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
670
    }
671
    event_add( c->c_read_event, c->c_read_timeout );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
672
673

    Debug( LDAP_DEBUG_CONNS, "upstream_finish: "
674
675
676
            "%sconnection connid=%lu for backend server '%s' is ready for "
            "use\n",
            is_bindconn ? "bind " : "", c->c_connid, b->b_name.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
677

678
679
    backend_retry( b );
    return LDAP_SUCCESS;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
680
681
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
682
683
684
static void
upstream_tls_handshake_cb( evutil_socket_t s, short what, void *arg )
{
685
686
    LloadConnection *c = arg;
    LloadBackend *b;
687
    epoch_t epoch;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
688
689
690
691
692
693
694
695
696
697
698
    int rc = LDAP_SUCCESS;

    CONNECTION_LOCK(c);
    if ( what & EV_TIMEOUT ) {
        Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: "
                "connid=%lu, timeout reached, destroying\n",
                c->c_connid );
        goto fail;
    }
    b = c->c_private;

699
    rc = ldap_pvt_tls_connect( lload_tls_backend_ld, c->c_sb, b->b_host );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
    if ( rc < 0 ) {
        goto fail;
    }

    if ( rc == 0 ) {
        struct event_base *base = event_get_base( c->c_read_event );

        /*
         * We're finished, replace the callbacks
         *
         * This is deadlock-safe, since both share the same base - the one
         * that's just running us.
         */
        event_del( c->c_read_event );
        event_del( c->c_write_event );

716
        c->c_read_timeout = NULL;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
717
718
719
720
721
722
723
724
725
        event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST,
                connection_read_cb, c );
        event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
                connection_write_cb, c );
        Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: "
                "connid=%lu finished\n",
                c->c_connid );
        c->c_is_tls = LLOAD_TLS_ESTABLISHED;

726
        CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
727
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
728
        CONNECTION_LOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
729
730
731
732

        rc = upstream_finish( c );
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );

733
734
        if ( rc ) {
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
735
736
737
738
739
740
741
        }
    } else if ( ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_NEEDS_WRITE, NULL ) ) {
        event_add( c->c_write_event, lload_write_timeout );
        Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: "
                "connid=%lu need write rc=%d\n",
                c->c_connid, rc );
    }
742
    CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
743
744
745
746
747
748
    return;

fail:
    Debug( LDAP_DEBUG_CONNS, "upstream_tls_handshake_cb: "
            "connid=%lu failed rc=%d\n",
            c->c_connid, rc );
749
750
751

    assert( c->c_ops == NULL );
    epoch = epoch_join();
Ondřej Kuzník's avatar
Ondřej Kuzník committed
752
    CONNECTION_DESTROY(c);
753
    epoch_leave( epoch );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
754
755
756
}

static int
757
upstream_starttls( LloadConnection *c )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
758
759
760
761
762
763
764
765
766
{
    BerValue matcheddn, message, responseOid,
             startTLSOid = BER_BVC(LDAP_EXOP_START_TLS);
    BerElement *ber = c->c_currentber;
    struct event_base *base;
    ber_int_t msgid, result;
    ber_tag_t tag;

    c->c_currentber = NULL;
767
    CONNECTION_LOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
768
769
770
771
772
773
774
775
776
777

    if ( ber_scanf( ber, "it", &msgid, &tag ) == LBER_ERROR ) {
        Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
                "protocol violation from server\n" );
        goto fail;
    }

    if ( msgid != ( c->c_next_msgid - 1 ) || tag != LDAP_RES_EXTENDED ) {
        Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
                "unexpected %s from server, msgid=%d\n",
778
                lload_msgtype2str( tag ), msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
        goto fail;
    }

    if ( ber_scanf( ber, "{emm}", &result, &matcheddn, &message ) ==
                 LBER_ERROR ) {
        Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
                "protocol violation on StartTLS response\n" );
        goto fail;
    }

    if ( (tag = ber_get_tag( ber )) != LBER_DEFAULT ) {
        if ( tag != LDAP_TAG_EXOP_RES_OID ||
                ber_scanf( ber, "{m}", &responseOid ) == LBER_DEFAULT ) {
            Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
                    "protocol violation on StartTLS response\n" );
            goto fail;
        }

        if ( ber_bvcmp( &responseOid, &startTLSOid ) ) {
            Debug( LDAP_DEBUG_ANY, "upstream_starttls: "
                    "oid=%s not a StartTLS response\n",
                    responseOid.bv_val );
            goto fail;
        }
    }

    if ( result != LDAP_SUCCESS ) {
806
        LloadBackend *b = c->c_private;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
807
808
809
810
811
812
813
814
815
816
817
        int rc;

        Debug( LDAP_DEBUG_STATS, "upstream_starttls: "
                "server doesn't support StartTLS rc=%d message='%s'%s\n",
                result, message.bv_val,
                (c->c_is_tls == LLOAD_STARTTLS_OPTIONAL) ? ", ignored" : "" );
        if ( c->c_is_tls != LLOAD_STARTTLS_OPTIONAL ) {
            goto fail;
        }
        c->c_is_tls = LLOAD_CLEARTEXT;

818
        CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
819
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
820
        CONNECTION_LOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
821
822
823
824

        rc = upstream_finish( c );
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );

825
826
        if ( rc ) {
            goto fail;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
827
828
        }

829
        ber_free( ber, 1 );
830
        CONNECTION_UNLOCK(c);
831

Ondřej Kuzník's avatar
Ondřej Kuzník committed
832
833
834
835
836
837
838
839
        return rc;
    }

    base = event_get_base( c->c_read_event );

    event_del( c->c_read_event );
    event_del( c->c_write_event );

840
    c->c_read_timeout = lload_timeout_net;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
841
842
843
844
845
    event_assign( c->c_read_event, base, c->c_fd, EV_READ|EV_PERSIST,
            upstream_tls_handshake_cb, c );
    event_assign( c->c_write_event, base, c->c_fd, EV_WRITE,
            upstream_tls_handshake_cb, c );

846
    event_add( c->c_read_event, c->c_read_timeout );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
847
848
849
850
851
852
853
854
855
856
857
858
859
    event_add( c->c_write_event, lload_write_timeout );

    CONNECTION_UNLOCK(c);

    ber_free( ber, 1 );
    return -1;

fail:
    ber_free( ber, 1 );
    CONNECTION_DESTROY(c);
    return -1;
}

860
861
862
/*
 * We must already hold b->b_mutex when called.
 */
863
864
LloadConnection *
upstream_init( ber_socket_t s, LloadBackend *b )
865
{
866
867
    LloadConnection *c;
    struct event_base *base = lload_get_base( s );
868
    struct event *event;
869
    int flags;
870
871
872

    assert( b != NULL );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
873
    flags = (b->b_proto == LDAP_PROTO_IPC) ? CONN_IS_IPC : 0;
874
    if ( (c = lload_connection_init( s, b->b_host, flags )) == NULL ) {
875
876
877
        return NULL;
    }

878
    CONNECTION_LOCK(c);
879
    c->c_private = b;
880
881
    c->c_is_tls = b->b_tls;
    c->c_pdu_cb = handle_one_response;
882

Ondřej Kuzník's avatar
Ondřej Kuzník committed
883
    LDAP_CIRCLEQ_INSERT_HEAD( &b->b_preparing, c, c_next );
884
    c->c_type = LLOAD_C_PREPARING;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
885

886
887
888
889
890
    {
        ber_len_t max = sockbuf_max_incoming_upstream;
        ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
    }

891
892
893
894
895
896
897
898
899
    event = event_new( base, s, EV_READ|EV_PERSIST, connection_read_cb, c );
    if ( !event ) {
        Debug( LDAP_DEBUG_ANY, "upstream_init: "
                "Read event could not be allocated\n" );
        goto fail;
    }
    c->c_read_event = event;

    event = event_new( base, s, EV_WRITE, connection_write_cb, c );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
900
    if ( !event ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
901
902
        Debug( LDAP_DEBUG_ANY, "upstream_init: "
                "Write event could not be allocated\n" );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
903
904
        goto fail;
    }
905
    /* We only add the write event when we have data pending */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
906
907
    c->c_write_event = event;

908
909
910
    c->c_destroy = upstream_destroy;
    c->c_unlink = upstream_unlink;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
911
    if ( c->c_is_tls == LLOAD_CLEARTEXT ) {
912
        if ( upstream_finish( c ) ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
913
914
915
916
917
            goto fail;
        }
    } else if ( c->c_is_tls == LLOAD_LDAPS ) {
        event_assign( c->c_read_event, base, s, EV_READ|EV_PERSIST,
                upstream_tls_handshake_cb, c );
918
        event_add( c->c_read_event, c->c_read_timeout );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
        event_assign( c->c_write_event, base, s, EV_WRITE,
                upstream_tls_handshake_cb, c );
        event_add( c->c_write_event, lload_write_timeout );
    } else if ( c->c_is_tls == LLOAD_STARTTLS ||
            c->c_is_tls == LLOAD_STARTTLS_OPTIONAL ) {
        BerElement *output;

        ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
        if ( (output = c->c_pendingber = ber_alloc()) == NULL ) {
            ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
            goto fail;
        }
        ber_printf( output, "t{tit{ts}}", LDAP_TAG_MESSAGE,
                LDAP_TAG_MSGID, c->c_next_msgid++,
                LDAP_REQ_EXTENDED,
                LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_START_TLS );
        ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
936

Ondřej Kuzník's avatar
Ondřej Kuzník committed
937
        c->c_pdu_cb = upstream_starttls;
938
        CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
939
        connection_write_cb( s, 0, c );
940
        CONNECTION_LOCK(c);
941
942
943
        if ( IS_ALIVE( c, c_live ) ) {
            event_add( c->c_read_event, c->c_read_timeout );
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
944
    }
945
    CONNECTION_UNLOCK(c);
Ondřej Kuzník's avatar
Ondřej Kuzník committed
946

Ondřej Kuzník's avatar
Ondřej Kuzník committed
947
    return c;
948

Ondřej Kuzník's avatar
Ondřej Kuzník committed
949
950
951
952
953
954
955
956
957
fail:
    if ( c->c_write_event ) {
        event_del( c->c_write_event );
        event_free( c->c_write_event );
    }
    if ( c->c_read_event ) {
        event_del( c->c_read_event );
        event_free( c->c_read_event );
    }
958

959
    c->c_state = LLOAD_C_INVALID;
960
961
962
    c->c_live--;
    c->c_refcnt--;
    connection_destroy( c );
963

Ondřej Kuzník's avatar
Ondřej Kuzník committed
964
965
966
    return NULL;
}

967
968
static void
upstream_unlink( LloadConnection *c )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
969
{
970
    LloadBackend *b = c->c_private;
971
    struct event *read_event, *write_event;
972
    TAvlnode *root;
973
    long freed, executing;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
974

975
976
    Debug( LDAP_DEBUG_CONNS, "upstream_unlink: "
            "removing upstream connid=%lu\n",
977
978
            c->c_connid );

979
    assert( c->c_state != LLOAD_C_INVALID );
980
    assert( c->c_state != LLOAD_C_DYING );
981

982
    c->c_state = LLOAD_C_DYING;
983

984
985
    read_event = c->c_read_event;
    write_event = c->c_write_event;
986

987
988
989
990
    root = c->c_ops;
    c->c_ops = NULL;
    executing = c->c_n_ops_executing;
    c->c_n_ops_executing = 0;
991

992
    CONNECTION_UNLOCK(c);
993

994
    freed = tavl_free( root, (AVL_FREE)operation_lost_upstream );
995
    assert( freed == executing );
996

997
998
999
1000
1001
    /*
     * Avoid a deadlock:
     * event_del will block if the event is currently executing its callback,
     * that callback might be waiting to lock c->c_mutex
     */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1002
1003
1004
    if ( read_event ) {
        event_del( read_event );
    }
1005

Ondřej Kuzník's avatar
Ondřej Kuzník committed
1006
1007
1008
    if ( write_event ) {
        event_del( write_event );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1009

1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
    if ( c->c_type == LLOAD_C_PREPARING ) {
        LDAP_CIRCLEQ_REMOVE( &b->b_preparing, c, c_next );
        b->b_opening--;
        b->b_failed++;
    } else if ( c->c_type == LLOAD_C_BIND ) {
        if ( c == b->b_last_bindconn ) {
            LloadConnection *prev =
                    LDAP_CIRCLEQ_LOOP_PREV( &b->b_bindconns, c, c_next );
            if ( prev == c ) {
                b->b_last_bindconn = NULL;
            } else {
                b->b_last_bindconn = prev;
1023
            }
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
        }
        LDAP_CIRCLEQ_REMOVE( &b->b_bindconns, c, c_next );
        b->b_bindavail--;
    } else {
        if ( c == b->b_last_conn ) {
            LloadConnection *prev =
                    LDAP_CIRCLEQ_LOOP_PREV( &b->b_conns, c, c_next );
            if ( prev == c ) {
                b->b_last_conn = NULL;
            } else {
                b->b_last_conn = prev;
1035
            }
1036
        }
1037
1038
        LDAP_CIRCLEQ_REMOVE( &b->b_conns, c, c_next );
        b->b_active--;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1039
    }
1040
1041
1042
    b->b_n_ops_executing -= executing;
    backend_retry( b );
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
1043

1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
    CONNECTION_LOCK(c);
}

void
upstream_destroy( LloadConnection *c )
{
    Debug( LDAP_DEBUG_CONNS, "upstream_destroy: "
            "freeing connection connid=%lu\n",
            c->c_connid );

    CONNECTION_LOCK(c);
    assert( c->c_state == LLOAD_C_DYING );
    c->c_state = LLOAD_C_INVALID;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1057

1058
1059
    assert( c->c_ops == NULL );

Ondřej Kuzník's avatar
Ondřej Kuzník committed
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
    if ( c->c_read_event ) {
        event_free( c->c_read_event );
        c->c_read_event = NULL;
    }

    if ( c->c_write_event ) {
        event_free( c->c_write_event );
        c->c_write_event = NULL;
    }

1070
1071
    if ( c->c_type != LLOAD_C_BIND ) {
        BER_BVZERO( &c->c_sasl_bind_mech );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1072
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1073
1074
    connection_destroy( c );
}