bind.c 9.75 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
24
25
26
/* $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>

#include "lutil.h"
#include "slap.h"

Ondřej Kuzník's avatar
Ondřej Kuzník committed
27
28
29
/*
 * We hold op->o_upstream->c_io_mutex on entering the function.
 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
30
31
32
static int
request_bind( Operation *op )
{
Ondřej Kuzník's avatar
Ondřej Kuzník committed
33
    Connection *client = op->o_client, *upstream = op->o_upstream;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
34
35
36
37
38
    BerElement *ber, *copy = NULL;
    BerValue binddn;
    ber_tag_t tag;
    ber_int_t version;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
39
    ber = upstream->c_pendingber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
40
41
42
43
44
    if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
        Debug( LDAP_DEBUG_ANY, "request_bind: "
                "ber_alloc failed\n" );
        goto fail;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
45
    upstream->c_pendingber = ber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
46
47
48
49
50
51
52
53
54
55

    if ( (copy = ber_alloc()) == NULL ) {
        goto fail;
    }
    ber_init2( copy, &op->o_request, 0 );

    tag = ber_get_int( copy, &version );
    if ( tag == LBER_ERROR ) {
        goto fail;
    } else if ( version != LDAP_VERSION3 ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
56
        ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
57
        operation_send_reject(
58
                op, LDAP_PROTOCOL_ERROR, "LDAP version unsupported", 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
59
60
61
62
63
64
65
66
67
        ber_free( copy, 0 );
        return 0;
    }

    tag = ber_get_stringbv( copy, &binddn, LBER_BV_NOTERM );
    if ( tag == LBER_ERROR ) {
        goto fail;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
68
69
70
    ldap_pvt_thread_mutex_lock( &client->c_mutex );
    if ( !BER_BVISNULL( &client->c_auth ) ) {
        ch_free( client->c_auth.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
71
72
73
74
    }

    if ( !BER_BVISEMPTY( &binddn ) ) {
        char *ptr;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
75
76
        client->c_auth.bv_len = STRLENOF("dn:") + binddn.bv_len;
        client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
77

Ondřej Kuzník's avatar
Ondřej Kuzník committed
78
        ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
79
80
81
        ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len );
        *ptr = '\0';
    } else {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
82
        BER_BVZERO( &client->c_auth );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
83
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
84
    ldap_pvt_thread_mutex_unlock( &client->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
85

Ondřej Kuzník's avatar
Ondřej Kuzník committed
86
87
    ldap_pvt_thread_mutex_lock( &upstream->c_mutex );
    op->o_upstream_msgid = upstream->c_next_msgid++;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
88
89
90
91
92
93

    ber_printf( ber, "t{titOtO}", LDAP_TAG_MESSAGE,
            LDAP_TAG_MSGID, op->o_upstream_msgid,
            LDAP_REQ_BIND, &op->o_request,
            LDAP_TAG_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) );

94
95
96
97
    Debug( LDAP_DEBUG_TRACE, "request_bind: "
            "added bind from client connid=%lu to upstream connid=%lu as "
            "msgid=%d\n",
            op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
98
99
    if ( tavl_insert( &upstream->c_ops, op, operation_upstream_cmp,
                 avl_dup_error ) ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
100
101
        assert(0);
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
102
    ldap_pvt_thread_mutex_unlock( &upstream->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
103

Ondřej Kuzník's avatar
Ondřej Kuzník committed
104
    ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
105
106

    ber_free( copy, 0 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
107
    upstream_write_cb( -1, 0, upstream );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
108
109
110
111
112
113
    return 0;

fail:
    if ( copy ) {
        ber_free( copy, 0 );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
114
    ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
115
116
117
118
119
    ldap_pvt_thread_mutex_lock( &op->o_client->c_mutex );
    client_destroy( op->o_client );
    return 1;
}

Ondřej Kuzník's avatar
Ondřej Kuzník committed
120
121
122
/*
 * We hold op->o_upstream->c_io_mutex on entering the function.
 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
123
124
125
static int
request_bind_as_vc( Operation *op )
{
Ondřej Kuzník's avatar
Ondřej Kuzník committed
126
    Connection *client = op->o_client, *upstream = op->o_upstream;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
127
128
    BerElement *ber, *request, *copy = NULL;
    BerValue binddn, auth, mech;
129
130
    char *msg = "internal error";
    int result = LDAP_OTHER;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
131
132
133
134
135
136
137
138
139
140
141
    ber_int_t version;
    ber_tag_t tag;
    ber_len_t len;

    if ( (request = ber_alloc()) == NULL ) {
        goto fail;
    }
    ber_init2( request, &op->o_request, 0 );

    tag = ber_scanf( request, "im", &version, &binddn );
    if ( tag == LBER_ERROR || version != LDAP_VERSION3 ) {
142
143
        result = LDAP_PROTOCOL_ERROR;
        msg = "version not recognised";
Ondřej Kuzník's avatar
Ondřej Kuzník committed
144
145
146
147
148
149
150
151
152
153
        goto fail;
    }

    copy = ber_dup( request );
    if ( !copy ) {
        goto fail;
    }

    tag = ber_skip_element( request, &auth );
    if ( tag == LBER_ERROR ) {
154
155
        result = LDAP_PROTOCOL_ERROR;
        msg = "malformed bind request";
Ondřej Kuzník's avatar
Ondřej Kuzník committed
156
157
158
        goto fail;
    }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
159
    ber = upstream->c_pendingber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
160
161
162
163
164
    if ( ber == NULL && (ber = ber_alloc()) == NULL ) {
        Debug( LDAP_DEBUG_ANY, "request_bind_as_vc: "
                "ber_alloc failed\n" );
        goto fail;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
165
    upstream->c_pendingber = ber;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
166

Ondřej Kuzník's avatar
Ondřej Kuzník committed
167
    op->o_upstream_msgid = upstream->c_next_msgid++;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
168

Ondřej Kuzník's avatar
Ondřej Kuzník committed
169
    ldap_pvt_thread_mutex_lock( &upstream->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
170
171
172
173
174
    ber_printf( ber, "t{tit{tst{{tOOtOtO}}}}", LDAP_TAG_MESSAGE,
            LDAP_TAG_MSGID, op->o_upstream_msgid,
            LDAP_REQ_EXTENDED,
            LDAP_TAG_EXOP_REQ_OID, LDAP_EXOP_VERIFY_CREDENTIALS,
            LDAP_TAG_EXOP_REQ_VALUE,
Ondřej Kuzník's avatar
Ondřej Kuzník committed
175
            LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, BER_BV_OPTIONAL( &upstream->c_vc_cookie ),
Ondřej Kuzník's avatar
Ondřej Kuzník committed
176
177
            &binddn, tag, &auth,
            LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS, BER_BV_OPTIONAL( &op->o_ctrls ) );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
178
    ldap_pvt_thread_mutex_unlock( &upstream->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
179
180
181
182
183

    tag = ber_peek_tag( copy, &len );
    switch ( tag ) {
        case LDAP_AUTH_SASL:
            ber_get_stringbv( copy, &mech, LBER_BV_NOTERM );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
184
185
186
187
188

            ldap_pvt_thread_mutex_lock( &client->c_mutex );
            if ( ber_bvcmp( &mech, &client->c_sasl_bind_mech ) ) {
                ber_memfree( client->c_sasl_bind_mech.bv_val );
                ber_dupbv( &client->c_sasl_bind_mech, &mech );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
189
            }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
190
            ldap_pvt_thread_mutex_unlock( &client->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
191
192
193
            /* TODO: extract authzdn from the message */
            break;
        case LDAP_AUTH_SIMPLE:
Ondřej Kuzník's avatar
Ondřej Kuzník committed
194
195
196
            ldap_pvt_thread_mutex_lock( &client->c_mutex );
            if ( !BER_BVISNULL( &client->c_auth ) ) {
                ch_free( client->c_auth.bv_val );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
197
            }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
198
199
            if ( !BER_BVISEMPTY( &binddn ) ) {
                char *ptr;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
200
201
                client->c_auth.bv_len = STRLENOF("dn:") + binddn.bv_len;
                client->c_auth.bv_val = ch_malloc( client->c_auth.bv_len + 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
202

Ondřej Kuzník's avatar
Ondřej Kuzník committed
203
                ptr = lutil_strcopy( client->c_auth.bv_val, "dn:" );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
204
205
206
                ptr = lutil_strncopy( ptr, binddn.bv_val, binddn.bv_len );
                *ptr = '\0';
            } else {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
207
                BER_BVZERO( &client->c_auth );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
208
209
            }

Ondřej Kuzník's avatar
Ondřej Kuzník committed
210
211
212
            if ( !BER_BVISNULL( &client->c_sasl_bind_mech ) ) {
                ber_memfree( client->c_sasl_bind_mech.bv_val );
                BER_BVZERO( &client->c_sasl_bind_mech );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
213
            }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
214
            ldap_pvt_thread_mutex_unlock( &client->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
215
216
            break;
        default:
217
218
            result = LDAP_PROTOCOL_ERROR;
            msg = "malformed bind request";
Ondřej Kuzník's avatar
Ondřej Kuzník committed
219
220
            goto fail;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
221
222

    ldap_pvt_thread_mutex_lock( &upstream->c_mutex );
223
224
225
226
    Debug( LDAP_DEBUG_TRACE, "request_bind_as_vc: "
            "added bind from client connid=%lu to upstream connid=%lu as VC "
            "exop msgid=%d\n",
            op->o_client_connid, op->o_upstream_connid, op->o_upstream_msgid );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
227
228
    if ( tavl_insert( &upstream->c_ops, op, operation_upstream_cmp,
                 avl_dup_error ) ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
229
230
        assert(0);
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
231
    ldap_pvt_thread_mutex_unlock( &upstream->c_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
232

Ondřej Kuzník's avatar
Ondřej Kuzník committed
233
    ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
234
235

    ber_free( copy, 0 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
236
    upstream_write_cb( -1, 0, upstream );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
237
238
239
240
241
242
    return 0;

fail:
    if ( copy ) {
        ber_free( copy, 0 );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
243
    ldap_pvt_thread_mutex_unlock( &upstream->c_io_mutex );
244
    operation_send_reject( op, result, msg, 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
245
246
    ldap_pvt_thread_mutex_lock( &client->c_mutex );
    client_destroy( client );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
    return 1;
}

void *
client_reset( void *ctx, void *arg )
{
    Operation *op = arg;
    Connection *c = op->o_client;
    TAvlnode *root;
    int freed, destroy = 1;

    ldap_pvt_thread_mutex_lock( &c->c_mutex );
    root = c->c_ops;
    c->c_ops = NULL;
    c->c_state = SLAP_C_CLOSING;
    if ( op->o_tag == LDAP_REQ_BIND ) {
        c->c_state = SLAP_C_BINDING;
        destroy = 0;
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
266
267
268
269
270
271
272
273
    if ( !BER_BVISNULL( &c->c_auth ) ) {
        ch_free( c->c_auth.bv_val );
        BER_BVZERO( &c->c_auth );
    }
    if ( !BER_BVISNULL( &c->c_sasl_bind_mech ) ) {
        ch_free( c->c_sasl_bind_mech.bv_val );
        BER_BVZERO( &c->c_sasl_bind_mech );
    }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
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
    ldap_pvt_thread_mutex_unlock( &c->c_mutex );

    tavl_delete( &root, op, operation_client_cmp );
    freed = tavl_free( root, (AVL_FREE)operation_abandon );

    Debug( LDAP_DEBUG_TRACE, "client_reset: "
            "dropped %d operations\n",
            freed );

    if ( destroy ) {
        operation_destroy( op );
        ldap_pvt_thread_mutex_lock( &c->c_mutex );
        client_destroy( c );
    }

    return NULL;
}

void *
client_bind( void *ctx, void *arg )
{
    Operation *op = arg;
    Connection *upstream, *client = op->o_client;
    int rc = 0;

    client_reset( ctx, arg );

    upstream = backend_select( op );
    if ( !upstream ) {
        Debug( LDAP_DEBUG_STATS, "client_bind: "
                "no available connection found\n" );
        operation_send_reject(
306
                op, LDAP_UNAVAILABLE, "no connections available", 1 );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
307
308
309
310
        return NULL;
    }

    op->o_upstream = upstream;
311
    op->o_upstream_connid = upstream->c_connid;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
312
    if ( lload_features & LLOAD_FEATURE_VC ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
        rc = request_bind_as_vc( op );
    } else {
        rc = request_bind( op );
    }

    if ( rc ) {
        /* client doesn't exist anymore */
        return NULL;
    }

    ldap_pvt_thread_mutex_lock( &client->c_mutex );
    rc = tavl_insert( &client->c_ops, op, operation_client_cmp, avl_dup_error );
    assert( rc == LDAP_SUCCESS );
    ldap_pvt_thread_mutex_unlock( &client->c_mutex );

    return NULL;
}