~ubuntu-branches/ubuntu/feisty/openldap2.3/feisty-security

« back to all changes in this revision

Viewing changes to servers/slapd/back-ldap/bind.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthijs Mohlmann
  • Date: 2006-11-11 11:24:42 UTC
  • Revision ID: james.westby@ubuntu.com-20061111112442-645qqio2u3fin0sj
Tags: upstream-2.3.29
ImportĀ upstreamĀ versionĀ 2.3.29

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* bind.c - ldap backend bind function */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/bind.c,v 1.85.2.27 2006/05/09 20:00:36 ando Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 1999-2006 The OpenLDAP Foundation.
 
6
 * Portions Copyright 2000-2003 Pierangelo Masarati.
 
7
 * Portions Copyright 1999-2003 Howard Chu.
 
8
 * All rights reserved.
 
9
 *
 
10
 * Redistribution and use in source and binary forms, with or without
 
11
 * modification, are permitted only as authorized by the OpenLDAP
 
12
 * Public License.
 
13
 *
 
14
 * A copy of this license is available in the file LICENSE in the
 
15
 * top-level directory of the distribution or, alternatively, at
 
16
 * <http://www.OpenLDAP.org/license.html>.
 
17
 */
 
18
/* ACKNOWLEDGEMENTS:
 
19
 * This work was initially developed by Howard Chu for inclusion
 
20
 * in OpenLDAP Software and subsequently enhanced by Pierangelo
 
21
 * Masarati.
 
22
 */
 
23
 
 
24
#include "portable.h"
 
25
 
 
26
#include <stdio.h>
 
27
 
 
28
#include <ac/errno.h>
 
29
#include <ac/socket.h>
 
30
#include <ac/string.h>
 
31
 
 
32
#define AVL_INTERNAL
 
33
#include "slap.h"
 
34
#include "back-ldap.h"
 
35
 
 
36
#include <lutil_ldap.h>
 
37
 
 
38
#ifndef PRINT_CONNTREE
 
39
#define PRINT_CONNTREE 0
 
40
#endif /* !PRINT_CONNTREE */
 
41
 
 
42
#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ       "2.16.840.1.113730.3.4.12"
 
43
 
 
44
static LDAP_REBIND_PROC ldap_back_default_rebind;
 
45
 
 
46
LDAP_REBIND_PROC        *ldap_back_rebind_f = ldap_back_default_rebind;
 
47
 
 
48
static int
 
49
ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
 
50
 
 
51
static int
 
52
ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
 
53
 
 
54
static int
 
55
ldap_back_conndnlc_cmp( const void *c1, const void *c2 );
 
56
 
 
57
int
 
58
ldap_back_bind( Operation *op, SlapReply *rs )
 
59
{
 
60
        ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
 
61
        ldapconn_t      *lc;
 
62
 
 
63
        int rc = 0;
 
64
        ber_int_t msgid;
 
65
 
 
66
        lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR );
 
67
        if ( !lc ) {
 
68
                return rs->sr_err;
 
69
        }
 
70
 
 
71
        if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
 
72
                ch_free( lc->lc_bound_ndn.bv_val );
 
73
                BER_BVZERO( &lc->lc_bound_ndn );
 
74
        }
 
75
        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
76
 
 
77
        /* method is always LDAP_AUTH_SIMPLE if we got here */
 
78
        rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
 
79
                        LDAP_SASL_SIMPLE,
 
80
                        &op->orb_cred, op->o_ctrls, NULL, &msgid );
 
81
        rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
 
82
 
 
83
        if ( rc == LDAP_SUCCESS ) {
 
84
                /* If defined, proxyAuthz will be used also when
 
85
                 * back-ldap is the authorizing backend; for this
 
86
                 * purpose, a successful bind is followed by a
 
87
                 * bind with the configured identity assertion */
 
88
                /* NOTE: use with care */
 
89
                if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
 
90
                        ldap_back_proxy_authz_bind( lc, op, rs, LDAP_BACK_SENDERR );
 
91
                        if ( !LDAP_BACK_CONN_ISBOUND( lc ) ) {
 
92
                                rc = 1;
 
93
                                goto done;
 
94
                        }
 
95
                }
 
96
 
 
97
                LDAP_BACK_CONN_ISBOUND_SET( lc );
 
98
                ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
 
99
 
 
100
                if ( LDAP_BACK_SAVECRED( li ) ) {
 
101
                        if ( !BER_BVISNULL( &lc->lc_cred ) ) {
 
102
                                memset( lc->lc_cred.bv_val, 0,
 
103
                                                lc->lc_cred.bv_len );
 
104
                        }
 
105
                        ber_bvreplace( &lc->lc_cred, &op->orb_cred );
 
106
                        ldap_set_rebind_proc( lc->lc_ld, ldap_back_rebind_f, lc );
 
107
                }
 
108
        }
 
109
done:;
 
110
 
 
111
        assert( lc->lc_binding == 1 );
 
112
        lc->lc_binding = 0;
 
113
 
 
114
        /* must re-insert if local DN changed as result of bind */
 
115
        if ( !LDAP_BACK_CONN_ISBOUND( lc )
 
116
                || ( LDAP_BACK_CONN_ISBOUND( lc )
 
117
                        && !dn_match( &op->o_req_ndn, &lc->lc_local_ndn ) ) )
 
118
        {
 
119
                int             lerr = -1;
 
120
                ldapconn_t      *tmplc;
 
121
 
 
122
                /* wait for all other ops to release the connection */
 
123
retry_lock:;
 
124
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
125
                if ( lc->lc_refcnt > 1 ) {
 
126
                        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
127
                        ldap_pvt_thread_yield();
 
128
                        goto retry_lock;
 
129
                }
 
130
 
 
131
                assert( lc->lc_refcnt == 1 );
 
132
                tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
 
133
                                ldap_back_conndnlc_cmp );
 
134
                assert( tmplc == NULL || lc == tmplc );
 
135
 
 
136
                if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
 
137
                        ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
 
138
                        lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
 
139
                                ldap_back_conndn_cmp, ldap_back_conndn_dup );
 
140
                }
 
141
 
 
142
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
143
                switch ( lerr ) {
 
144
                case 0:
 
145
                        break;
 
146
 
 
147
                case -1:
 
148
                        /* duplicate; someone else successfully bound
 
149
                         * on the same connection with the same identity;
 
150
                         * we can do this because lc_refcnt == 1 */
 
151
                        ldap_back_conn_free( lc );
 
152
                        lc = NULL;
 
153
                }
 
154
        }
 
155
 
 
156
        if ( lc != NULL ) {
 
157
                ldap_back_release_conn( op, rs, lc );
 
158
        }
 
159
 
 
160
        return( rc );
 
161
}
 
162
 
 
163
/*
 
164
 * ldap_back_conndn_cmp
 
165
 *
 
166
 * compares two ldapconn_t based on the value of the conn pointer
 
167
 * and of the local DN; used by avl stuff for insert, lookup
 
168
 * and direct delete
 
169
 */
 
170
int
 
171
ldap_back_conndn_cmp( const void *c1, const void *c2 )
 
172
{
 
173
        const ldapconn_t        *lc1 = (const ldapconn_t *)c1;
 
174
        const ldapconn_t        *lc2 = (const ldapconn_t *)c2;
 
175
        int rc;
 
176
 
 
177
        /* If local DNs don't match, it is definitely not a match */
 
178
        /* For shared sessions, conn is NULL. Only explicitly
 
179
         * bound sessions will have non-NULL conn.
 
180
         */
 
181
        rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
 
182
        if ( rc == 0 ) {
 
183
                rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
 
184
        }
 
185
 
 
186
        return rc;
 
187
}
 
188
 
 
189
/*
 
190
 * ldap_back_conndnlc_cmp
 
191
 *
 
192
 * compares two ldapconn_t based on the value of the conn pointer,
 
193
 * the local DN and the lc pointer; used by avl stuff for insert, lookup
 
194
 * and direct delete
 
195
 */
 
196
static int
 
197
ldap_back_conndnlc_cmp( const void *c1, const void *c2 )
 
198
{
 
199
        const ldapconn_t        *lc1 = (const ldapconn_t *)c1;
 
200
        const ldapconn_t        *lc2 = (const ldapconn_t *)c2;
 
201
        int rc;
 
202
 
 
203
        /* If local DNs don't match, it is definitely not a match */
 
204
        /* For shared sessions, conn is NULL. Only explicitly
 
205
         * bound sessions will have non-NULL conn.
 
206
         */
 
207
        rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
 
208
        if ( rc == 0 ) {
 
209
                rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
 
210
                if ( rc == 0 ) {
 
211
                        rc = SLAP_PTRCMP( lc1, lc2 );
 
212
                }
 
213
        }
 
214
 
 
215
        return rc;
 
216
}
 
217
 
 
218
/*
 
219
 * ldap_back_conn_cmp
 
220
 *
 
221
 * compares two ldapconn_t based on the value of the conn pointer;
 
222
 * used by avl stuff for delete of all conns with the same connid
 
223
 */
 
224
int
 
225
ldap_back_conn_cmp( const void *c1, const void *c2 )
 
226
{
 
227
        const ldapconn_t        *lc1 = (const ldapconn_t *)c1;
 
228
        const ldapconn_t        *lc2 = (const ldapconn_t *)c2;
 
229
 
 
230
        /* For shared sessions, conn is NULL. Only explicitly
 
231
         * bound sessions will have non-NULL conn.
 
232
         */
 
233
        return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
 
234
}
 
235
 
 
236
/*
 
237
 * ldap_back_conndn_dup
 
238
 *
 
239
 * returns -1 in case a duplicate ldapconn_t has been inserted;
 
240
 * used by avl stuff
 
241
 */
 
242
int
 
243
ldap_back_conndn_dup( void *c1, void *c2 )
 
244
{
 
245
        ldapconn_t      *lc1 = (ldapconn_t *)c1;
 
246
        ldapconn_t      *lc2 = (ldapconn_t *)c2;
 
247
 
 
248
        /* Cannot have more than one shared session with same DN */
 
249
        if ( lc1->lc_conn == lc2->lc_conn &&
 
250
                dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
 
251
        {
 
252
                return -1;
 
253
        }
 
254
                
 
255
        return 0;
 
256
}
 
257
 
 
258
#if PRINT_CONNTREE > 0
 
259
static void
 
260
ravl_print( Avlnode *root, int depth )
 
261
{
 
262
        int             i;
 
263
        ldapconn_t      *lc;
 
264
        
 
265
        if ( root == 0 ) {
 
266
                return;
 
267
        }
 
268
        
 
269
        ravl_print( root->avl_right, depth+1 );
 
270
        
 
271
        for ( i = 0; i < depth; i++ ) {
 
272
                fprintf( stderr, "-" );
 
273
        }
 
274
 
 
275
        lc = root->avl_data;
 
276
        fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d\n",
 
277
                (void *)lc, lc->lc_local_ndn.bv_val, (void *)lc->lc_conn,
 
278
                avl_bf2str( root->avl_bf ), lc->lc_refcnt );
 
279
        
 
280
        ravl_print( root->avl_left, depth+1 );
 
281
}
 
282
 
 
283
static void
 
284
myprint( Avlnode *root )
 
285
{
 
286
        fprintf( stderr, "========>\n" );
 
287
        
 
288
        if ( root == 0 ) {
 
289
                fprintf( stderr, "\tNULL\n" );
 
290
 
 
291
        } else {
 
292
                ravl_print( root, 0 );
 
293
        }
 
294
        
 
295
        fprintf( stderr, "<========\n" );
 
296
}
 
297
#endif /* PRINT_CONNTREE */
 
298
 
 
299
int
 
300
ldap_back_freeconn( Operation *op, ldapconn_t *lc, int dolock )
 
301
{
 
302
        ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
 
303
        ldapconn_t      *tmplc;
 
304
 
 
305
        if ( dolock ) {
 
306
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
307
        }
 
308
 
 
309
        tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
 
310
                        ldap_back_conndnlc_cmp );
 
311
        assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
 
312
        if ( lc->lc_refcnt == 0 ) {
 
313
                ldap_back_conn_free( (void *)lc );
 
314
        }
 
315
 
 
316
        if ( dolock ) {
 
317
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
318
        }
 
319
 
 
320
        return 0;
 
321
}
 
322
 
 
323
#ifdef HAVE_TLS
 
324
static int
 
325
ldap_back_start_tls(
 
326
        LDAP            *ld,
 
327
        int             protocol,
 
328
        int             *is_tls,
 
329
        const char      *url,
 
330
        unsigned        flags,
 
331
        int             retries,
 
332
        const char      **text )
 
333
{
 
334
        int             rc = LDAP_SUCCESS;
 
335
        ldapinfo_t      dummy;
 
336
 
 
337
        /* this is ridiculous... */
 
338
        dummy.li_flags = flags;
 
339
 
 
340
        /* start TLS ("tls-[try-]{start,propagate}" statements) */
 
341
        if ( ( LDAP_BACK_USE_TLS( &dummy ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS( &dummy ) ) )
 
342
                                && !ldap_is_ldaps_url( url ) )
 
343
        {
 
344
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
 
345
                /*
 
346
                 * use asynchronous StartTLS
 
347
                 * in case, chase referral (not implemented yet)
 
348
                 */
 
349
                int             msgid;
 
350
 
 
351
                if ( protocol == 0 ) {
 
352
                        ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
 
353
                                        (void *)&protocol );
 
354
                }
 
355
 
 
356
                if ( protocol < LDAP_VERSION3 ) {
 
357
                        protocol = LDAP_VERSION3;
 
358
                        /* Set LDAP version */
 
359
                        ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
 
360
                                        (const void *)&protocol );
 
361
                }
 
362
 
 
363
                rc = ldap_start_tls( ld, NULL, NULL, &msgid );
 
364
                if ( rc == LDAP_SUCCESS ) {
 
365
                        LDAPMessage     *res = NULL;
 
366
                        struct timeval  tv;
 
367
 
 
368
                        LDAP_BACK_TV_SET( &tv );
 
369
 
 
370
retry:;
 
371
                        rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
 
372
                        if ( rc < 0 ) {
 
373
                                rc = LDAP_UNAVAILABLE;
 
374
 
 
375
                        } else if ( rc == 0 ) {
 
376
                                if ( retries != LDAP_BACK_RETRY_NEVER ) {
 
377
                                        ldap_pvt_thread_yield();
 
378
                                        if ( retries > 0 ) {
 
379
                                                retries--;
 
380
                                        }
 
381
                                        LDAP_BACK_TV_SET( &tv );
 
382
                                        goto retry;
 
383
                                }
 
384
                                rc = LDAP_UNAVAILABLE;
 
385
 
 
386
                        } else if ( rc == LDAP_RES_EXTENDED ) {
 
387
                                struct berval   *data = NULL;
 
388
 
 
389
                                rc = ldap_parse_extended_result( ld, res,
 
390
                                                NULL, &data, 0 );
 
391
                                if ( rc == LDAP_SUCCESS ) {
 
392
                                        int err;
 
393
                                        rc = ldap_parse_result( ld, res, &err,
 
394
                                                NULL, NULL, NULL, NULL, 1 );
 
395
                                        if ( rc == LDAP_SUCCESS ) {
 
396
                                                rc = err;
 
397
                                        }
 
398
                                        res = NULL;
 
399
                                        
 
400
                                        /* FIXME: in case a referral 
 
401
                                         * is returned, should we try
 
402
                                         * using it instead of the 
 
403
                                         * configured URI? */
 
404
                                        if ( rc == LDAP_SUCCESS ) {
 
405
                                                rc = ldap_install_tls( ld );
 
406
 
 
407
                                        } else if ( rc == LDAP_REFERRAL ) {
 
408
                                                rc = LDAP_UNWILLING_TO_PERFORM;
 
409
                                                *text = "unwilling to chase referral returned by Start TLS exop";
 
410
                                        }
 
411
 
 
412
                                        if ( data ) {
 
413
                                                if ( data->bv_val ) {
 
414
                                                        ber_memfree( data->bv_val );
 
415
                                                }
 
416
                                                ber_memfree( data );
 
417
                                        }
 
418
                                }
 
419
 
 
420
                        } else {
 
421
                                rc = LDAP_OTHER;
 
422
                        }
 
423
 
 
424
                        if ( res != NULL ) {
 
425
                                ldap_msgfree( res );
 
426
                        }
 
427
                }
 
428
#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
 
429
                /*
 
430
                 * use synchronous StartTLS
 
431
                 */
 
432
                rc = ldap_start_tls_s( ld, NULL, NULL );
 
433
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
 
434
 
 
435
                /* if StartTLS is requested, only attempt it if the URL
 
436
                 * is not "ldaps://"; this may occur not only in case
 
437
                 * of misconfiguration, but also when used in the chain 
 
438
                 * overlay, where the "uri" can be parsed out of a referral */
 
439
                switch ( rc ) {
 
440
                case LDAP_SUCCESS:
 
441
                        *is_tls = 1;
 
442
                        break;
 
443
 
 
444
                case LDAP_SERVER_DOWN:
 
445
                        break;
 
446
 
 
447
                default:
 
448
                        if ( LDAP_BACK_TLS_CRITICAL( &dummy ) ) {
 
449
                                *text = "could not start TLS";
 
450
                                break;
 
451
                        }
 
452
 
 
453
                        /* in case Start TLS is not critical */
 
454
                        *is_tls = 0;
 
455
                        rc = LDAP_SUCCESS;
 
456
                        break;
 
457
                }
 
458
 
 
459
        } else {
 
460
                *is_tls = 0;
 
461
        }
 
462
 
 
463
        return rc;
 
464
}
 
465
#endif /* HAVE_TLS */
 
466
 
 
467
static int
 
468
ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
 
469
{
 
470
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
471
        int             vers = op->o_protocol;
 
472
        LDAP            *ld = NULL;
 
473
#ifdef HAVE_TLS
 
474
        int             is_tls = op->o_conn->c_is_tls;
 
475
#endif /* HAVE_TLS */
 
476
 
 
477
        assert( lcp != NULL );
 
478
 
 
479
        rs->sr_err = ldap_initialize( &ld, li->li_uri );
 
480
        if ( rs->sr_err != LDAP_SUCCESS ) {
 
481
                goto error_return;
 
482
        }
 
483
 
 
484
        /* Set LDAP version. This will always succeed: If the client
 
485
         * bound with a particular version, then so can we.
 
486
         */
 
487
        if ( vers == 0 ) {
 
488
                /* assume it's an internal op; set to LDAPv3 */
 
489
                vers = LDAP_VERSION3;
 
490
        }
 
491
        ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
 
492
 
 
493
        /* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
 
494
        ldap_set_option( ld, LDAP_OPT_REFERRALS,
 
495
                LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
 
496
 
 
497
        if ( li->li_network_timeout > 0 ) {
 
498
                struct timeval          tv;
 
499
 
 
500
                tv.tv_sec = li->li_network_timeout;
 
501
                tv.tv_usec = 0;
 
502
                ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
 
503
        }
 
504
 
 
505
#ifdef HAVE_TLS
 
506
        rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
 
507
                        li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text );
 
508
        if ( rs->sr_err != LDAP_SUCCESS ) {
 
509
                ldap_unbind_ext( ld, NULL, NULL );
 
510
                goto error_return;
 
511
        }
 
512
#endif /* HAVE_TLS */
 
513
 
 
514
        if ( *lcp == NULL ) {
 
515
                *lcp = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
 
516
                (*lcp)->lc_flags= li->li_flags;
 
517
        }
 
518
        (*lcp)->lc_ld = ld;
 
519
        (*lcp)->lc_refcnt = 1;
 
520
        (*lcp)->lc_binding = 1;
 
521
#ifdef HAVE_TLS
 
522
        if ( is_tls ) {
 
523
                LDAP_BACK_CONN_ISTLS_SET( *lcp );
 
524
        } else {
 
525
                LDAP_BACK_CONN_ISTLS_CLEAR( *lcp );
 
526
        }
 
527
#endif /* HAVE_TLS */
 
528
 
 
529
error_return:;
 
530
        if ( rs->sr_err != LDAP_SUCCESS ) {
 
531
                rs->sr_err = slap_map_api2result( rs );
 
532
                if ( sendok & LDAP_BACK_SENDERR ) {
 
533
                        if ( rs->sr_text == NULL ) {
 
534
                                rs->sr_text = "ldap_initialize() failed";
 
535
                        }
 
536
                        send_ldap_result( op, rs );
 
537
                        rs->sr_text = NULL;
 
538
                }
 
539
 
 
540
        } else {
 
541
                if ( li->li_conn_ttl > 0 ) {
 
542
                        (*lcp)->lc_create_time = op->o_time;
 
543
                }
 
544
        }
 
545
 
 
546
        return rs->sr_err;
 
547
}
 
548
 
 
549
ldapconn_t *
 
550
ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
 
551
{
 
552
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
553
        ldapconn_t      *lc = NULL,
 
554
                        lc_curr = { 0 };
 
555
        int             refcnt = 1, binding = 1;
 
556
 
 
557
        /* Internal searches are privileged and shared. So is root. */
 
558
        if ( op->o_do_not_cache || be_isroot( op ) ) {
 
559
                LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
 
560
                lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
 
561
                lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
 
562
 
 
563
        } else {
 
564
                lc_curr.lc_local_ndn = op->o_ndn;
 
565
                /* Explicit binds must not be shared */
 
566
                if ( op->o_tag == LDAP_REQ_BIND || SLAP_IS_AUTHZ_BACKEND( op ) ) {
 
567
                        lc_curr.lc_conn = op->o_conn;
 
568
        
 
569
                } else {
 
570
                        lc_curr.lc_conn = LDAP_BACK_PCONN_SET( op );
 
571
                }
 
572
        }
 
573
 
 
574
        /* Explicit Bind requests always get their own conn */
 
575
        if ( !( sendok & LDAP_BACK_BINDING ) ) {
 
576
                /* Searches for a ldapconn in the avl tree */
 
577
retry_lock:
 
578
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
579
 
 
580
                lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
 
581
                                (caddr_t)&lc_curr, ldap_back_conndn_cmp );
 
582
                if ( lc != NULL ) {
 
583
                        /* Don't reuse connections while they're still binding */
 
584
                        if ( LDAP_BACK_CONN_BINDING( lc ) ) {
 
585
                                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
586
                                ldap_pvt_thread_yield();
 
587
                                goto retry_lock;
 
588
                        }
 
589
                        refcnt = ++lc->lc_refcnt;
 
590
                        binding = ++lc->lc_binding;
 
591
                }
 
592
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
593
        }
 
594
 
 
595
        /* Looks like we didn't get a bind. Open a new session... */
 
596
        if ( lc == NULL ) {
 
597
                if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
 
598
                        return NULL;
 
599
                }
 
600
                if ( sendok & LDAP_BACK_BINDING ) {
 
601
                        LDAP_BACK_CONN_BINDING_SET( lc );
 
602
                }
 
603
                lc->lc_conn = lc_curr.lc_conn;
 
604
                ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
 
605
 
 
606
                if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
 
607
                        ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
 
608
                        ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
 
609
                        LDAP_BACK_CONN_ISPRIV_SET( lc );
 
610
 
 
611
                } else {
 
612
                        BER_BVZERO( &lc->lc_cred );
 
613
                        BER_BVZERO( &lc->lc_bound_ndn );
 
614
#if 0
 
615
                        /* FIXME: if we set lc_bound_ndn = o_ndn
 
616
                         * we end up with a bind with DN but no password! */
 
617
                        if ( !BER_BVISEMPTY( &op->o_ndn )
 
618
                                && SLAP_IS_AUTHZ_BACKEND( op ) )
 
619
                        {
 
620
                                ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
 
621
                        }
 
622
#endif
 
623
                }
 
624
 
 
625
#ifdef HAVE_TLS
 
626
                /* if start TLS failed but it was not mandatory,
 
627
                 * check if the non-TLS connection was already
 
628
                 * in cache; in case, destroy the newly created
 
629
                 * connection and use the existing one */
 
630
                if ( lc->lc_conn == LDAP_BACK_PCONN_TLS
 
631
                                && !ldap_tls_inplace( lc->lc_ld ) )
 
632
                {
 
633
                        ldapconn_t *tmplc;
 
634
                        
 
635
                        lc_curr.lc_conn = LDAP_BACK_PCONN;
 
636
                        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
637
                        tmplc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
 
638
                                        (caddr_t)&lc_curr, ldap_back_conndn_cmp );
 
639
                        if ( tmplc != NULL ) {
 
640
                                refcnt = ++tmplc->lc_refcnt;
 
641
                                binding = ++tmplc->lc_binding;
 
642
                                ldap_back_conn_free( lc );
 
643
                                lc = tmplc;
 
644
                        }
 
645
                        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
646
 
 
647
                        if ( tmplc != NULL ) {
 
648
                                goto done;
 
649
                        }
 
650
                }
 
651
#endif /* HAVE_TLS */
 
652
 
 
653
                LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
654
 
 
655
                /* Inserts the newly created ldapconn in the avl tree */
 
656
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
657
 
 
658
                assert( lc->lc_refcnt == 1 );
 
659
                assert( lc->lc_binding == 1 );
 
660
                rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
 
661
                        ldap_back_conndn_cmp, ldap_back_conndn_dup );
 
662
 
 
663
#if PRINT_CONNTREE > 0
 
664
                myprint( li->li_conninfo.lai_tree );
 
665
#endif /* PRINT_CONNTREE */
 
666
        
 
667
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
668
 
 
669
                Debug( LDAP_DEBUG_TRACE,
 
670
                        "=>ldap_back_getconn: conn %p inserted refcnt=%u binding=%u\n",
 
671
                        (void *)lc, refcnt, binding );
 
672
        
 
673
                /* Err could be -1 in case a duplicate ldapconn is inserted */
 
674
                switch ( rs->sr_err ) {
 
675
                case 0:
 
676
                        break;
 
677
 
 
678
                case -1:
 
679
                        if ( !( sendok & LDAP_BACK_BINDING ) ) {
 
680
                                /* duplicate: free and try to get the newly created one */
 
681
                                goto retry_lock;
 
682
                        }
 
683
                        /* taint connection, so that it'll be freed when released */
 
684
                        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
685
                        (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
 
686
                                        ldap_back_conndnlc_cmp );
 
687
                        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
688
                        LDAP_BACK_CONN_TAINTED_SET( lc );
 
689
                        break;
 
690
 
 
691
                default:
 
692
                        ldap_back_conn_free( lc );
 
693
                        rs->sr_err = LDAP_OTHER;
 
694
                        rs->sr_text = "proxy bind collision";
 
695
                        if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
 
696
                                send_ldap_result( op, rs );
 
697
                                rs->sr_text = NULL;
 
698
                        }
 
699
                        return NULL;
 
700
                }
 
701
 
 
702
        } else {
 
703
                char    buf[ SLAP_TEXT_BUFLEN ];
 
704
                int     expiring = 0;
 
705
 
 
706
                if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
 
707
                        || ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
 
708
                {
 
709
                        expiring = 1;
 
710
 
 
711
                        /* let it be used, but taint/delete it so that 
 
712
                         * no-one else can look it up any further */
 
713
                        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
714
                        (void *)avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
 
715
                                        ldap_back_conndnlc_cmp );
 
716
                        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
717
                        LDAP_BACK_CONN_TAINTED_SET( lc );
 
718
                }
 
719
 
 
720
                {
 
721
                        snprintf( buf, sizeof( buf ),
 
722
                                "conn %p fetched refcnt=%u binding=%u%s",
 
723
                                (void *)lc, refcnt, binding, expiring ? " expiring" : "" );
 
724
                        Debug( LDAP_DEBUG_TRACE,
 
725
                                "=>ldap_back_getconn: %s.\n", buf, 0, 0 );
 
726
                }
 
727
        
 
728
        }
 
729
 
 
730
#ifdef HAVE_TLS
 
731
done:;
 
732
#endif /* HAVE_TLS */
 
733
        if ( li->li_idle_timeout && lc ) {
 
734
                lc->lc_time = op->o_time;
 
735
        }
 
736
 
 
737
        return lc;
 
738
}
 
739
 
 
740
void
 
741
ldap_back_release_conn_lock(
 
742
        Operation               *op,
 
743
        SlapReply               *rs,
 
744
        ldapconn_t              *lc,
 
745
        int                     dolock )
 
746
{
 
747
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
748
 
 
749
        if ( dolock ) {
 
750
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
751
        }
 
752
        assert( lc->lc_refcnt > 0 );
 
753
        LDAP_BACK_CONN_BINDING_CLEAR( lc );
 
754
        lc->lc_refcnt--;
 
755
        if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
 
756
                ldap_back_freeconn( op, lc, 0 );
 
757
        }
 
758
        if ( dolock ) {
 
759
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
760
        }
 
761
}
 
762
 
 
763
/*
 
764
 * ldap_back_dobind
 
765
 *
 
766
 * Note: as the check for the value of lc->lc_bound was already here, I removed
 
767
 * it from all the callers, and I made the function return the flag, so
 
768
 * it can be used to simplify the check.
 
769
 *
 
770
 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not
 
771
 */
 
772
static int
 
773
ldap_back_dobind_int(
 
774
        ldapconn_t              *lc,
 
775
        Operation               *op,
 
776
        SlapReply               *rs,
 
777
        ldap_back_send_t        sendok,
 
778
        int                     retries,
 
779
        int                     dolock )
 
780
{       
 
781
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
782
 
 
783
        int             rc, binding = 0;
 
784
        ber_int_t       msgid;
 
785
 
 
786
        assert( retries >= 0 );
 
787
 
 
788
retry_lock:;
 
789
        if ( dolock ) {
 
790
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
791
        }
 
792
 
 
793
        if ( binding == 0 ) {
 
794
                /* check if already bound */
 
795
                rc = LDAP_BACK_CONN_ISBOUND( lc );
 
796
                if ( rc ) {
 
797
                        lc->lc_binding--;
 
798
                        if ( dolock ) {
 
799
                                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
800
                        }
 
801
                        return rc;
 
802
                }
 
803
 
 
804
                if ( LDAP_BACK_CONN_BINDING( lc ) ) {
 
805
                        /* if someone else is about to bind it, give up and retry */
 
806
                        if ( dolock ) {
 
807
                                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
808
                        }
 
809
                        ldap_pvt_thread_yield();
 
810
                        goto retry_lock;
 
811
 
 
812
                } else {
 
813
                        /* otherwise this thread will bind it */
 
814
                        LDAP_BACK_CONN_BINDING_SET( lc );
 
815
                        binding = 1;
 
816
                }
 
817
        }
 
818
 
 
819
        /* wait for pending operations to finish */
 
820
        /* FIXME: may become a bottleneck! */
 
821
        if ( lc->lc_refcnt != lc->lc_binding ) {
 
822
                if ( dolock ) {
 
823
                        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
824
                }
 
825
                ldap_pvt_thread_yield();
 
826
                goto retry_lock;
 
827
        }
 
828
 
 
829
        if ( dolock ) {
 
830
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
831
        }
 
832
 
 
833
#if 0
 
834
        while ( lc->lc_refcnt > 1 ) {
 
835
                ldap_pvt_thread_yield();
 
836
                rc = LDAP_BACK_CONN_ISBOUND( lc );
 
837
                if ( rc ) {
 
838
                        return rc;
 
839
                }
 
840
        }
 
841
 
 
842
        if ( dolock ) {
 
843
                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
844
        }
 
845
        LDAP_BACK_CONN_BINDING_SET( lc );
 
846
        if ( dolock ) {
 
847
                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
848
        }
 
849
#endif
 
850
 
 
851
        /*
 
852
         * FIXME: we need to let clients use proxyAuthz
 
853
         * otherwise we cannot do symmetric pools of servers;
 
854
         * we have to live with the fact that a user can
 
855
         * authorize itself as any ID that is allowed
 
856
         * by the authzTo directive of the "proxyauthzdn".
 
857
         */
 
858
        /*
 
859
         * NOTE: current Proxy Authorization specification
 
860
         * and implementation do not allow proxy authorization
 
861
         * control to be provided with Bind requests
 
862
         */
 
863
        /*
 
864
         * if no bind took place yet, but the connection is bound
 
865
         * and the "idassert-authcDN" (or other ID) is set, 
 
866
         * then bind as the asserting identity and explicitly 
 
867
         * add the proxyAuthz control to every operation with the
 
868
         * dn bound to the connection as control value.
 
869
         * This is done also if this is the authrizing backend,
 
870
         * but the "override" flag is given to idassert.
 
871
         * It allows to use SASL bind and yet proxyAuthz users
 
872
         */
 
873
        if ( op->o_conn != NULL &&
 
874
                        !op->o_do_not_cache &&
 
875
                        ( BER_BVISNULL( &lc->lc_bound_ndn ) ||
 
876
                          ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
 
877
        {
 
878
                (void)ldap_back_proxy_authz_bind( lc, op, rs, sendok );
 
879
                goto done;
 
880
        }
 
881
 
 
882
#ifdef HAVE_CYRUS_SASL
 
883
        if ( LDAP_BACK_CONN_ISPRIV( lc )
 
884
                && li->li_acl_authmethod == LDAP_AUTH_SASL )
 
885
        {
 
886
                void            *defaults = NULL;
 
887
 
 
888
                if ( li->li_acl_secprops != NULL ) {
 
889
                        rc = ldap_set_option( lc->lc_ld,
 
890
                                LDAP_OPT_X_SASL_SECPROPS, li->li_acl_secprops);
 
891
 
 
892
                        if ( rc != LDAP_OPT_SUCCESS ) {
 
893
                                Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option "
 
894
                                        "(%s,SECPROPS,\"%s\") failed!\n",
 
895
                                        li->li_uri, li->li_acl_secprops, 0 );
 
896
                                goto done;
 
897
                        }
 
898
                }
 
899
 
 
900
                defaults = lutil_sasl_defaults( lc->lc_ld,
 
901
                                li->li_acl_sasl_mech.bv_val,
 
902
                                li->li_acl_sasl_realm.bv_val,
 
903
                                li->li_acl_authcID.bv_val,
 
904
                                li->li_acl_passwd.bv_val,
 
905
                                NULL );
 
906
 
 
907
                rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld,
 
908
                                li->li_acl_authcDN.bv_val,
 
909
                                li->li_acl_sasl_mech.bv_val, NULL, NULL,
 
910
                                LDAP_SASL_QUIET, lutil_sasl_interact,
 
911
                                defaults );
 
912
 
 
913
                lutil_sasl_freedefs( defaults );
 
914
 
 
915
                rs->sr_err = slap_map_api2result( rs );
 
916
                if ( rs->sr_err != LDAP_SUCCESS ) {
 
917
                        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
918
                        send_ldap_result( op, rs );
 
919
 
 
920
                } else {
 
921
                        LDAP_BACK_CONN_ISBOUND_SET( lc );
 
922
                }
 
923
                goto done;
 
924
        }
 
925
#endif /* HAVE_CYRUS_SASL */
 
926
 
 
927
retry:;
 
928
        rs->sr_err = ldap_sasl_bind( lc->lc_ld,
 
929
                        lc->lc_bound_ndn.bv_val,
 
930
                        LDAP_SASL_SIMPLE, &lc->lc_cred,
 
931
                        NULL, NULL, &msgid );
 
932
 
 
933
        if ( rs->sr_err == LDAP_SERVER_DOWN ) {
 
934
                if ( retries != LDAP_BACK_RETRY_NEVER ) {
 
935
                        if ( dolock ) {
 
936
                                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
937
                        }
 
938
 
 
939
                        assert( lc->lc_refcnt > 0 );
 
940
                        if ( lc->lc_refcnt == 1 ) {
 
941
                                ldap_unbind_ext( lc->lc_ld, NULL, NULL );
 
942
                                lc->lc_ld = NULL;
 
943
 
 
944
                                /* lc here must be the regular lc, reset and ready for init */
 
945
                                rs->sr_err = ldap_back_prepare_conn( &lc, op, rs, sendok );
 
946
                                if ( rs->sr_err != LDAP_SUCCESS ) {
 
947
                                        lc->lc_binding--;
 
948
                                        lc->lc_refcnt = 0;
 
949
                                }
 
950
                        }
 
951
 
 
952
                        if ( dolock ) {
 
953
                                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
954
                        }
 
955
 
 
956
                        if ( rs->sr_err == LDAP_SUCCESS ) {
 
957
                                if ( retries > 0 ) {
 
958
                                        retries--;
 
959
                                }
 
960
                                goto retry;
 
961
                        }
 
962
 
 
963
                } else {
 
964
                        if ( dolock ) {
 
965
                                ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
966
                        }
 
967
                        lc->lc_binding--;
 
968
                        if ( dolock ) {
 
969
                                ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
970
                        }
 
971
                }
 
972
 
 
973
                ldap_back_freeconn( op, lc, dolock );
 
974
                rs->sr_err = slap_map_api2result( rs );
 
975
 
 
976
                return 0;
 
977
        }
 
978
 
 
979
        rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
 
980
        if ( rc == LDAP_SUCCESS ) {
 
981
                LDAP_BACK_CONN_ISBOUND_SET( lc );
 
982
        }
 
983
 
 
984
done:;
 
985
        lc->lc_binding--;
 
986
        LDAP_BACK_CONN_BINDING_CLEAR( lc );
 
987
        rc = LDAP_BACK_CONN_ISBOUND( lc );
 
988
        if ( !rc ) {
 
989
                ldap_back_release_conn_lock( op, rs, lc, dolock );
 
990
        }
 
991
 
 
992
        return rc;
 
993
}
 
994
 
 
995
int
 
996
ldap_back_dobind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
 
997
{
 
998
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
999
 
 
1000
        return ldap_back_dobind_int( lc, op, rs, sendok, li->li_nretries, 1 );
 
1001
}
 
1002
 
 
1003
/*
 
1004
 * ldap_back_default_rebind
 
1005
 *
 
1006
 * This is a callback used for chasing referrals using the same
 
1007
 * credentials as the original user on this session.
 
1008
 */
 
1009
static int 
 
1010
ldap_back_default_rebind( LDAP *ld, LDAP_CONST char *url, ber_tag_t request,
 
1011
        ber_int_t msgid, void *params )
 
1012
{
 
1013
        ldapconn_t      *lc = (ldapconn_t *)params;
 
1014
 
 
1015
#ifdef HAVE_TLS
 
1016
        /* ... otherwise we couldn't get here */
 
1017
        assert( lc != NULL );
 
1018
 
 
1019
        if ( !ldap_tls_inplace( ld ) ) {
 
1020
                int             is_tls = LDAP_BACK_CONN_ISTLS( lc ),
 
1021
                                rc;
 
1022
                const char      *text = NULL;
 
1023
 
 
1024
                rc = ldap_back_start_tls( ld, 0, &is_tls, url, lc->lc_flags,
 
1025
                        LDAP_BACK_RETRY_DEFAULT, &text );
 
1026
                if ( rc != LDAP_SUCCESS ) {
 
1027
                        return rc;
 
1028
                }
 
1029
        }
 
1030
#endif /* HAVE_TLS */
 
1031
 
 
1032
        /* FIXME: add checks on the URL/identity? */
 
1033
 
 
1034
        return ldap_sasl_bind_s( ld, lc->lc_bound_ndn.bv_val,
 
1035
                        LDAP_SASL_SIMPLE, &lc->lc_cred, NULL, NULL, NULL );
 
1036
}
 
1037
 
 
1038
int
 
1039
ldap_back_op_result(
 
1040
                ldapconn_t              *lc,
 
1041
                Operation               *op,
 
1042
                SlapReply               *rs,
 
1043
                ber_int_t               msgid,
 
1044
                time_t                  timeout,
 
1045
                ldap_back_send_t        sendok )
 
1046
{
 
1047
        char            *match = NULL;
 
1048
        LDAPMessage     *res = NULL;
 
1049
        char            *text = NULL;
 
1050
 
 
1051
#define ERR_OK(err) ((err) == LDAP_SUCCESS || (err) == LDAP_COMPARE_FALSE || (err) == LDAP_COMPARE_TRUE)
 
1052
 
 
1053
        rs->sr_text = NULL;
 
1054
        rs->sr_matched = NULL;
 
1055
 
 
1056
        /* if the error recorded in the reply corresponds
 
1057
         * to a successful state, get the error from the
 
1058
         * remote server response */
 
1059
        if ( ERR_OK( rs->sr_err ) ) {
 
1060
                int             rc;
 
1061
                struct timeval  tv;
 
1062
 
 
1063
                if ( timeout ) {
 
1064
                        tv.tv_sec = timeout;
 
1065
                        tv.tv_usec = 0;
 
1066
 
 
1067
                } else {
 
1068
                        LDAP_BACK_TV_SET( &tv );
 
1069
                }
 
1070
 
 
1071
retry:;
 
1072
                /* if result parsing fails, note the failure reason */
 
1073
                rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
 
1074
                switch ( rc ) {
 
1075
                case 0:
 
1076
                        if ( timeout ) {
 
1077
                                (void)ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL );
 
1078
                                rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
 
1079
                                        LDAP_ADMINLIMIT_EXCEEDED : LDAP_OPERATIONS_ERROR;
 
1080
                                rs->sr_text = "Operation timed out";
 
1081
                                break;
 
1082
                        }
 
1083
 
 
1084
                        LDAP_BACK_TV_SET( &tv );
 
1085
                        ldap_pvt_thread_yield();
 
1086
                        goto retry;
 
1087
 
 
1088
                case -1:
 
1089
                        ldap_get_option( lc->lc_ld, LDAP_OPT_ERROR_NUMBER,
 
1090
                                        &rs->sr_err );
 
1091
                        break;
 
1092
 
 
1093
 
 
1094
                /* otherwise get the result; if it is not
 
1095
                 * LDAP_SUCCESS, record it in the reply
 
1096
                 * structure (this includes 
 
1097
                 * LDAP_COMPARE_{TRUE|FALSE}) */
 
1098
                default:
 
1099
                        rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err,
 
1100
                                        &match, &text, NULL, NULL, 1 );
 
1101
#ifndef LDAP_NULL_IS_NULL
 
1102
                        if ( match != NULL && match[ 0 ] == '\0' ) {
 
1103
                                ldap_memfree( match );
 
1104
                                match = NULL;
 
1105
                        }
 
1106
                        if ( text != NULL && text[ 0 ] == '\0' ) {
 
1107
                                ldap_memfree( text );
 
1108
                                text = NULL;
 
1109
                        }
 
1110
#endif /* LDAP_NULL_IS_NULL */
 
1111
                        rs->sr_text = text;
 
1112
                        if ( rc != LDAP_SUCCESS ) {
 
1113
                                rs->sr_err = rc;
 
1114
                        }
 
1115
                }
 
1116
        }
 
1117
 
 
1118
        /* if the error in the reply structure is not
 
1119
         * LDAP_SUCCESS, try to map it from client 
 
1120
         * to server error */
 
1121
        if ( !ERR_OK( rs->sr_err ) ) {
 
1122
                rs->sr_err = slap_map_api2result( rs );
 
1123
 
 
1124
                /* internal ops ( op->o_conn == NULL ) 
 
1125
                 * must not reply to client */
 
1126
                if ( op->o_conn && !op->o_do_not_cache && match ) {
 
1127
 
 
1128
                        /* record the (massaged) matched
 
1129
                         * DN into the reply structure */
 
1130
                        rs->sr_matched = match;
 
1131
                }
 
1132
        }
 
1133
        if ( op->o_conn &&
 
1134
                        ( ( sendok & LDAP_BACK_SENDOK ) 
 
1135
                          || ( ( sendok & LDAP_BACK_SENDERR ) && rs->sr_err != LDAP_SUCCESS ) ) )
 
1136
        {
 
1137
                send_ldap_result( op, rs );
 
1138
        }
 
1139
        if ( match ) {
 
1140
                if ( rs->sr_matched != match ) {
 
1141
                        free( (char *)rs->sr_matched );
 
1142
                }
 
1143
                rs->sr_matched = NULL;
 
1144
                ldap_memfree( match );
 
1145
        }
 
1146
        if ( text ) {
 
1147
                ldap_memfree( text );
 
1148
        }
 
1149
        rs->sr_text = NULL;
 
1150
        return( ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
 
1151
}
 
1152
 
 
1153
/* return true if bound, false if failed */
 
1154
int
 
1155
ldap_back_retry( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
 
1156
{
 
1157
        int             rc = 0;
 
1158
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
1159
 
 
1160
        assert( lcp != NULL );
 
1161
        assert( *lcp != NULL );
 
1162
 
 
1163
        ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
 
1164
 
 
1165
        if ( (*lcp)->lc_refcnt == 1 ) {
 
1166
                Debug( LDAP_DEBUG_ANY,
 
1167
                        "%s ldap_back_retry: retrying URI=\"%s\" DN=\"%s\"\n",
 
1168
                        op->o_log_prefix, li->li_uri,
 
1169
                        BER_BVISNULL( &(*lcp)->lc_bound_ndn ) ?
 
1170
                                "" : (*lcp)->lc_bound_ndn.bv_val );
 
1171
 
 
1172
                ldap_unbind_ext( (*lcp)->lc_ld, NULL, NULL );
 
1173
                (*lcp)->lc_ld = NULL;
 
1174
                LDAP_BACK_CONN_ISBOUND_CLEAR( (*lcp) );
 
1175
 
 
1176
                /* lc here must be the regular lc, reset and ready for init */
 
1177
                rc = ldap_back_prepare_conn( lcp, op, rs, sendok );
 
1178
                if ( rc != LDAP_SUCCESS ) {
 
1179
                        rc = 0;
 
1180
                        *lcp = NULL;
 
1181
 
 
1182
                } else {
 
1183
                        rc = ldap_back_dobind_int( *lcp, op, rs, sendok, 0, 0 );
 
1184
                        if ( rc == 0 ) {
 
1185
                                *lcp = NULL;
 
1186
                        }
 
1187
                }
 
1188
 
 
1189
        } else {
 
1190
                Debug( LDAP_DEBUG_TRACE,
 
1191
                        "ldap_back_retry: conn %p refcnt=%u unable to retry.\n",
 
1192
                        (void *)(*lcp), (*lcp)->lc_refcnt, 0 );
 
1193
 
 
1194
                ldap_back_release_conn_lock( op, rs, *lcp, 0 );
 
1195
                *lcp = NULL;
 
1196
 
 
1197
                if ( sendok ) {
 
1198
                        rs->sr_err = LDAP_UNAVAILABLE;
 
1199
                        rs->sr_text = "unable to retry";
 
1200
                        send_ldap_result( op, rs );
 
1201
                }
 
1202
        }
 
1203
 
 
1204
        ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
 
1205
 
 
1206
        return rc;
 
1207
}
 
1208
 
 
1209
static int
 
1210
ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
 
1211
{
 
1212
        ldapinfo_t      *li = (ldapinfo_t *)op->o_bd->be_private;
 
1213
        struct berval   binddn = slap_empty_bv;
 
1214
        struct berval   bindcred = slap_empty_bv;
 
1215
        struct berval   ndn;
 
1216
        int             dobind = 0;
 
1217
        int             msgid;
 
1218
        int             rc;
 
1219
 
 
1220
        if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
 
1221
                ndn = op->o_conn->c_ndn;
 
1222
 
 
1223
        } else {
 
1224
                ndn = op->o_ndn;
 
1225
        }
 
1226
 
 
1227
        /*
 
1228
         * FIXME: we need to let clients use proxyAuthz
 
1229
         * otherwise we cannot do symmetric pools of servers;
 
1230
         * we have to live with the fact that a user can
 
1231
         * authorize itself as any ID that is allowed
 
1232
         * by the authzTo directive of the "proxyauthzdn".
 
1233
         */
 
1234
        /*
 
1235
         * NOTE: current Proxy Authorization specification
 
1236
         * and implementation do not allow proxy authorization
 
1237
         * control to be provided with Bind requests
 
1238
         */
 
1239
        /*
 
1240
         * if no bind took place yet, but the connection is bound
 
1241
         * and the "proxyauthzdn" is set, then bind as 
 
1242
         * "proxyauthzdn" and explicitly add the proxyAuthz 
 
1243
         * control to every operation with the dn bound 
 
1244
         * to the connection as control value.
 
1245
         */
 
1246
 
 
1247
        /* bind as proxyauthzdn only if no idassert mode
 
1248
         * is requested, or if the client's identity
 
1249
         * is authorized */
 
1250
        switch ( li->li_idassert_mode ) {
 
1251
        case LDAP_BACK_IDASSERT_LEGACY:
 
1252
                if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
 
1253
                        if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
 
1254
                        {
 
1255
                                binddn = li->li_idassert_authcDN;
 
1256
                                bindcred = li->li_idassert_passwd;
 
1257
                                dobind = 1;
 
1258
                        }
 
1259
                }
 
1260
                break;
 
1261
 
 
1262
        default:
 
1263
                /* NOTE: rootdn can always idassert */
 
1264
                if ( BER_BVISNULL( &ndn ) && li->li_idassert_authz == NULL ) {
 
1265
                        if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
 
1266
                                rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
 
1267
                                if ( sendok & LDAP_BACK_SENDERR ) {
 
1268
                                        send_ldap_result( op, rs );
 
1269
                                }
 
1270
                                LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
1271
 
 
1272
                        } else {
 
1273
                                rs->sr_err = LDAP_SUCCESS;
 
1274
                                binddn = slap_empty_bv;
 
1275
                                bindcred = slap_empty_bv;
 
1276
                                break;
 
1277
                        }
 
1278
 
 
1279
                        goto done;
 
1280
 
 
1281
                } else if ( li->li_idassert_authz && !be_isroot( op ) ) {
 
1282
                        struct berval authcDN;
 
1283
 
 
1284
                        if ( BER_BVISNULL( &ndn ) ) {
 
1285
                                authcDN = slap_empty_bv;
 
1286
 
 
1287
                        } else {
 
1288
                                authcDN = ndn;
 
1289
                        }       
 
1290
                        rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
 
1291
                                        &authcDN, &authcDN );
 
1292
                        if ( rs->sr_err != LDAP_SUCCESS ) {
 
1293
                                if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
 
1294
                                        if ( sendok & LDAP_BACK_SENDERR ) {
 
1295
                                                send_ldap_result( op, rs );
 
1296
                                        }
 
1297
                                        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
1298
 
 
1299
                                } else {
 
1300
                                        rs->sr_err = LDAP_SUCCESS;
 
1301
                                        binddn = slap_empty_bv;
 
1302
                                        bindcred = slap_empty_bv;
 
1303
                                        break;
 
1304
                                }
 
1305
 
 
1306
                                goto done;
 
1307
                        }
 
1308
                }
 
1309
 
 
1310
                binddn = li->li_idassert_authcDN;
 
1311
                bindcred = li->li_idassert_passwd;
 
1312
                dobind = 1;
 
1313
                break;
 
1314
        }
 
1315
 
 
1316
        if ( dobind && li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
 
1317
#ifdef HAVE_CYRUS_SASL
 
1318
                void            *defaults = NULL;
 
1319
                struct berval   authzID = BER_BVNULL;
 
1320
                int             freeauthz = 0;
 
1321
 
 
1322
                /* if SASL supports native authz, prepare for it */
 
1323
                if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
 
1324
                                ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
 
1325
                {
 
1326
                        switch ( li->li_idassert_mode ) {
 
1327
                        case LDAP_BACK_IDASSERT_OTHERID:
 
1328
                        case LDAP_BACK_IDASSERT_OTHERDN:
 
1329
                                authzID = li->li_idassert_authzID;
 
1330
                                break;
 
1331
 
 
1332
                        case LDAP_BACK_IDASSERT_ANONYMOUS:
 
1333
                                BER_BVSTR( &authzID, "dn:" );
 
1334
                                break;
 
1335
 
 
1336
                        case LDAP_BACK_IDASSERT_SELF:
 
1337
                                if ( BER_BVISNULL( &ndn ) ) {
 
1338
                                        /* connection is not authc'd, so don't idassert */
 
1339
                                        BER_BVSTR( &authzID, "dn:" );
 
1340
                                        break;
 
1341
                                }
 
1342
                                authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
 
1343
                                authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
 
1344
                                AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
 
1345
                                AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
 
1346
                                                ndn.bv_val, ndn.bv_len + 1 );
 
1347
                                freeauthz = 1;
 
1348
                                break;
 
1349
 
 
1350
                        default:
 
1351
                                break;
 
1352
                        }
 
1353
                }
 
1354
 
 
1355
                if ( li->li_idassert_secprops != NULL ) {
 
1356
                        rs->sr_err = ldap_set_option( lc->lc_ld,
 
1357
                                LDAP_OPT_X_SASL_SECPROPS,
 
1358
                                (void *)li->li_idassert_secprops );
 
1359
 
 
1360
                        if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
 
1361
                                rs->sr_err = LDAP_OTHER;
 
1362
                                if ( sendok & LDAP_BACK_SENDERR ) {
 
1363
                                        send_ldap_result( op, rs );
 
1364
                                }
 
1365
                                LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
1366
                                goto done;
 
1367
                        }
 
1368
                }
 
1369
 
 
1370
                defaults = lutil_sasl_defaults( lc->lc_ld,
 
1371
                                li->li_idassert_sasl_mech.bv_val,
 
1372
                                li->li_idassert_sasl_realm.bv_val,
 
1373
                                li->li_idassert_authcID.bv_val,
 
1374
                                li->li_idassert_passwd.bv_val,
 
1375
                                authzID.bv_val );
 
1376
 
 
1377
                rs->sr_err = ldap_sasl_interactive_bind_s( lc->lc_ld, binddn.bv_val,
 
1378
                                li->li_idassert_sasl_mech.bv_val, NULL, NULL,
 
1379
                                LDAP_SASL_QUIET, lutil_sasl_interact,
 
1380
                                defaults );
 
1381
 
 
1382
                rs->sr_err = slap_map_api2result( rs );
 
1383
                if ( rs->sr_err != LDAP_SUCCESS ) {
 
1384
                        LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
1385
                        if ( sendok & LDAP_BACK_SENDERR ) {
 
1386
                                send_ldap_result( op, rs );
 
1387
                        }
 
1388
 
 
1389
                } else {
 
1390
                        LDAP_BACK_CONN_ISBOUND_SET( lc );
 
1391
                }
 
1392
 
 
1393
                lutil_sasl_freedefs( defaults );
 
1394
                if ( freeauthz ) {
 
1395
                        slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
 
1396
                }
 
1397
 
 
1398
                goto done;
 
1399
#endif /* HAVE_CYRUS_SASL */
 
1400
        }
 
1401
 
 
1402
        switch ( li->li_idassert_authmethod ) {
 
1403
        case LDAP_AUTH_NONE:
 
1404
                LDAP_BACK_CONN_ISBOUND_SET( lc );
 
1405
                goto done;
 
1406
 
 
1407
        case LDAP_AUTH_SIMPLE:
 
1408
                rs->sr_err = ldap_sasl_bind( lc->lc_ld,
 
1409
                                binddn.bv_val, LDAP_SASL_SIMPLE,
 
1410
                                &bindcred, NULL, NULL, &msgid );
 
1411
                break;
 
1412
 
 
1413
        default:
 
1414
                /* unsupported! */
 
1415
                LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
 
1416
                rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
 
1417
                if ( sendok & LDAP_BACK_SENDERR ) {
 
1418
                        send_ldap_result( op, rs );
 
1419
                }
 
1420
                goto done;
 
1421
        }
 
1422
 
 
1423
        rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
 
1424
        if ( rc == LDAP_SUCCESS ) {
 
1425
                LDAP_BACK_CONN_ISBOUND_SET( lc );
 
1426
        }
 
1427
done:;
 
1428
        return LDAP_BACK_CONN_ISBOUND( lc );
 
1429
}
 
1430
 
 
1431
/*
 
1432
 * ldap_back_proxy_authz_ctrl() prepends a proxyAuthz control
 
1433
 * to existing server-side controls if required; if not,
 
1434
 * the existing server-side controls are placed in *pctrls.
 
1435
 * The caller, after using the controls in client API 
 
1436
 * operations, if ( *pctrls != op->o_ctrls ), should
 
1437
 * free( (*pctrls)[ 0 ] ) and free( *pctrls ).
 
1438
 * The function returns success if the control could
 
1439
 * be added if required, or if it did nothing; in the future,
 
1440
 * it might return some error if it failed.
 
1441
 * 
 
1442
 * if no bind took place yet, but the connection is bound
 
1443
 * and the "proxyauthzdn" is set, then bind as "proxyauthzdn" 
 
1444
 * and explicitly add proxyAuthz the control to every operation
 
1445
 * with the dn bound to the connection as control value.
 
1446
 *
 
1447
 * If no server-side controls are defined for the operation,
 
1448
 * simply add the proxyAuthz control; otherwise, if the
 
1449
 * proxyAuthz control is not already set, add it as
 
1450
 * the first one
 
1451
 *
 
1452
 * FIXME: is controls order significant for security?
 
1453
 * ANSWER: controls ordering and interoperability
 
1454
 * must be indicated by the specs of each control; if none
 
1455
 * is specified, the order is irrelevant.
 
1456
 */
 
1457
int
 
1458
ldap_back_proxy_authz_ctrl(
 
1459
                ldapconn_t      *lc,
 
1460
                Operation       *op,
 
1461
                SlapReply       *rs,
 
1462
                LDAPControl     ***pctrls )
 
1463
{
 
1464
        ldapinfo_t      *li = (ldapinfo_t *) op->o_bd->be_private;
 
1465
        LDAPControl     **ctrls = NULL;
 
1466
        int             i = 0,
 
1467
                        mode;
 
1468
        struct berval   assertedID,
 
1469
                        ndn;
 
1470
 
 
1471
        *pctrls = NULL;
 
1472
 
 
1473
        rs->sr_err = LDAP_SUCCESS;
 
1474
 
 
1475
        /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
 
1476
         * but if it is not set this test fails.  We need a different
 
1477
         * means to detect if idassert is enabled */
 
1478
        if ( ( BER_BVISNULL( &li->li_idassert_authcID ) || BER_BVISEMPTY( &li->li_idassert_authcID ) )
 
1479
                        && ( BER_BVISNULL( &li->li_idassert_authcDN ) || BER_BVISEMPTY( &li->li_idassert_authcDN ) ) )
 
1480
        {
 
1481
                goto done;
 
1482
        }
 
1483
 
 
1484
        if ( !op->o_conn || op->o_do_not_cache || be_isroot( op ) ) {
 
1485
                goto done;
 
1486
        }
 
1487
 
 
1488
        if ( op->o_tag == LDAP_REQ_BIND ) {
 
1489
                ndn = op->o_req_ndn;
 
1490
 
 
1491
        } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
 
1492
                ndn = op->o_conn->c_ndn;
 
1493
 
 
1494
        } else {
 
1495
                ndn = op->o_ndn;
 
1496
        }
 
1497
 
 
1498
        if ( li->li_idassert_mode == LDAP_BACK_IDASSERT_LEGACY ) {
 
1499
                if ( op->o_proxy_authz ) {
 
1500
                        /*
 
1501
                         * FIXME: we do not want to perform proxyAuthz
 
1502
                         * on behalf of the client, because this would
 
1503
                         * be performed with "proxyauthzdn" privileges.
 
1504
                         *
 
1505
                         * This might actually be too strict, since
 
1506
                         * the "proxyauthzdn" authzTo, and each entry's
 
1507
                         * authzFrom attributes may be crafted
 
1508
                         * to avoid unwanted proxyAuthz to take place.
 
1509
                         */
 
1510
#if 0
 
1511
                        rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
 
1512
                        rs->sr_text = "proxyAuthz not allowed within namingContext";
 
1513
#endif
 
1514
                        goto done;
 
1515
                }
 
1516
 
 
1517
                if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
 
1518
                        goto done;
 
1519
                }
 
1520
 
 
1521
                if ( BER_BVISNULL( &ndn ) ) {
 
1522
                        goto done;
 
1523
                }
 
1524
 
 
1525
                if ( BER_BVISNULL( &li->li_idassert_authcDN ) ) {
 
1526
                        goto done;
 
1527
                }
 
1528
 
 
1529
        } else if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
 
1530
                if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ )
 
1531
                                /* && ( !BER_BVISNULL( &ndn )
 
1532
                                        || LDAP_BACK_CONN_ISBOUND( lc ) ) */ )
 
1533
                {
 
1534
                        /* already asserted in SASL via native authz */
 
1535
                        /* NOTE: the test on lc->lc_bound is used to trap
 
1536
                         * native authorization of anonymous users,
 
1537
                         * since in that case ndn is NULL */
 
1538
                        goto done;
 
1539
                }
 
1540
 
 
1541
        } else if ( li->li_idassert_authz && !be_isroot( op ) ) {
 
1542
                int             rc;
 
1543
                struct berval authcDN;
 
1544
 
 
1545
                if ( BER_BVISNULL( &ndn ) ) {
 
1546
                        authcDN = slap_empty_bv;
 
1547
                } else {
 
1548
                        authcDN = ndn;
 
1549
                }
 
1550
                rc = slap_sasl_matches( op, li->li_idassert_authz,
 
1551
                                &authcDN, & authcDN );
 
1552
                if ( rc != LDAP_SUCCESS ) {
 
1553
                        if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE )
 
1554
                        {
 
1555
                                /* ndn is not authorized
 
1556
                                 * to use idassert */
 
1557
                                rs->sr_err = rc;
 
1558
                        }
 
1559
                        goto done;
 
1560
                }
 
1561
        }
 
1562
 
 
1563
        if ( op->o_proxy_authz ) {
 
1564
                /*
 
1565
                 * FIXME: we can:
 
1566
                 * 1) ignore the already set proxyAuthz control
 
1567
                 * 2) leave it in place, and don't set ours
 
1568
                 * 3) add both
 
1569
                 * 4) reject the operation
 
1570
                 *
 
1571
                 * option (4) is very drastic
 
1572
                 * option (3) will make the remote server reject
 
1573
                 * the operation, thus being equivalent to (4)
 
1574
                 * option (2) will likely break the idassert
 
1575
                 * assumptions, so we cannot accept it;
 
1576
                 * option (1) means that we are contradicting
 
1577
                 * the client's reques.
 
1578
                 *
 
1579
                 * I think (4) is the only correct choice.
 
1580
                 */
 
1581
                rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
 
1582
                rs->sr_text = "proxyAuthz not allowed within namingContext";
 
1583
        }
 
1584
 
 
1585
        if ( op->o_is_auth_check ) {
 
1586
                mode = LDAP_BACK_IDASSERT_NOASSERT;
 
1587
 
 
1588
        } else {
 
1589
                mode = li->li_idassert_mode;
 
1590
        }
 
1591
 
 
1592
        switch ( mode ) {
 
1593
        case LDAP_BACK_IDASSERT_SELF:
 
1594
                if ( BER_BVISNULL( &ndn ) ) {
 
1595
                        goto done;
 
1596
                }
 
1597
                assertedID = ndn;
 
1598
                break;
 
1599
 
 
1600
        case LDAP_BACK_IDASSERT_LEGACY:
 
1601
                /* original behavior:
 
1602
                 * assert the client's identity */
 
1603
                if ( BER_BVISNULL( &ndn ) ) {
 
1604
                        assertedID = slap_empty_bv;
 
1605
                } else {
 
1606
                        assertedID = ndn;
 
1607
                }
 
1608
                break;
 
1609
 
 
1610
        case LDAP_BACK_IDASSERT_ANONYMOUS:
 
1611
                /* assert "anonymous" */
 
1612
                assertedID = slap_empty_bv;
 
1613
                break;
 
1614
 
 
1615
        case LDAP_BACK_IDASSERT_NOASSERT:
 
1616
                /* don't assert; bind as proxyauthzdn */
 
1617
                goto done;
 
1618
 
 
1619
        case LDAP_BACK_IDASSERT_OTHERID:
 
1620
        case LDAP_BACK_IDASSERT_OTHERDN:
 
1621
                /* assert idassert DN */
 
1622
                assertedID = li->li_idassert_authzID;
 
1623
                break;
 
1624
 
 
1625
        default:
 
1626
                assert( 0 );
 
1627
        }
 
1628
 
 
1629
        if ( BER_BVISNULL( &assertedID ) ) {
 
1630
                assertedID = slap_empty_bv;
 
1631
        }
 
1632
 
 
1633
        /* don't idassert the bound DN (ITS#4497) */
 
1634
        if ( dn_match( &assertedID, &lc->lc_bound_ndn ) ) {
 
1635
                goto done;
 
1636
        }
 
1637
 
 
1638
        if ( op->o_ctrls ) {
 
1639
                for ( i = 0; op->o_ctrls[ i ]; i++ )
 
1640
                        /* just count ctrls */ ;
 
1641
        }
 
1642
 
 
1643
        ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + 2) + sizeof( LDAPControl ),
 
1644
                        op->o_tmpmemctx );
 
1645
        ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + 2 ];
 
1646
        
 
1647
        ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
 
1648
        ctrls[ 0 ]->ldctl_iscritical = 1;
 
1649
 
 
1650
        switch ( li->li_idassert_mode ) {
 
1651
        /* already in u:ID or dn:DN form */
 
1652
        case LDAP_BACK_IDASSERT_OTHERID:
 
1653
        case LDAP_BACK_IDASSERT_OTHERDN:
 
1654
                ber_dupbv_x( &ctrls[ 0 ]->ldctl_value, &assertedID, op->o_tmpmemctx );
 
1655
                break;
 
1656
 
 
1657
        /* needs the dn: prefix */
 
1658
        default:
 
1659
                ctrls[ 0 ]->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
 
1660
                ctrls[ 0 ]->ldctl_value.bv_val = op->o_tmpalloc( ctrls[ 0 ]->ldctl_value.bv_len + 1,
 
1661
                                op->o_tmpmemctx );
 
1662
                AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
 
1663
                AC_MEMCPY( &ctrls[ 0 ]->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
 
1664
                                assertedID.bv_val, assertedID.bv_len + 1 );
 
1665
                break;
 
1666
        }
 
1667
 
 
1668
        if ( op->o_ctrls ) {
 
1669
                for ( i = 0; op->o_ctrls[ i ]; i++ ) {
 
1670
                        ctrls[ i + 1 ] = op->o_ctrls[ i ];
 
1671
                }
 
1672
        }
 
1673
        ctrls[ i + 1 ] = NULL;
 
1674
 
 
1675
done:;
 
1676
        if ( ctrls == NULL ) {
 
1677
                ctrls = op->o_ctrls;
 
1678
        }
 
1679
 
 
1680
        *pctrls = ctrls;
 
1681
        
 
1682
        return rs->sr_err;
 
1683
}
 
1684
 
 
1685
int
 
1686
ldap_back_proxy_authz_ctrl_free( Operation *op, LDAPControl ***pctrls )
 
1687
{
 
1688
        LDAPControl     **ctrls = *pctrls;
 
1689
 
 
1690
        /* we assume that the first control is the proxyAuthz
 
1691
         * added by back-ldap, so it's the only one we explicitly 
 
1692
         * free */
 
1693
        if ( ctrls && ctrls != op->o_ctrls ) {
 
1694
                assert( ctrls[ 0 ] != NULL );
 
1695
 
 
1696
                if ( !BER_BVISNULL( &ctrls[ 0 ]->ldctl_value ) ) {
 
1697
                        op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
 
1698
                }
 
1699
 
 
1700
                op->o_tmpfree( ctrls, op->o_tmpmemctx );
 
1701
        } 
 
1702
 
 
1703
        *pctrls = NULL;
 
1704
 
 
1705
        return 0;
 
1706
}