~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* chain.c - chain LDAP operations */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/back-ldap/chain.c,v 1.52.2.7 2008/02/11 23:26:46 kurt Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2003-2008 The OpenLDAP Foundation.
 
6
 * Portions Copyright 2003 Howard Chu.
 
7
 * All rights reserved.
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted only as authorized by the OpenLDAP
 
11
 * Public License.
 
12
 *
 
13
 * A copy of this license is available in the file LICENSE in the
 
14
 * top-level directory of the distribution or, alternatively, at
 
15
 * <http://www.OpenLDAP.org/license.html>.
 
16
 */
 
17
/* ACKNOWLEDGEMENTS:
 
18
 * This work was initially developed by the Howard Chu for inclusion
 
19
 * in OpenLDAP Software.
 
20
 * This work was subsequently modified by Pierangelo Masarati.
 
21
 */
 
22
 
 
23
#include "portable.h"
 
24
 
 
25
#include <stdio.h>
 
26
 
 
27
#include <ac/string.h>
 
28
#include <ac/socket.h>
 
29
 
 
30
#include "lutil.h"
 
31
#include "slap.h"
 
32
#include "back-ldap.h"
 
33
#include "config.h"
 
34
 
 
35
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
36
#define SLAP_CHAINING_DEFAULT                           LDAP_CHAINING_PREFERRED
 
37
#define SLAP_CH_RESOLVE_SHIFT                           SLAP_CONTROL_SHIFT
 
38
#define SLAP_CH_RESOLVE_MASK                            (0x3 << SLAP_CH_RESOLVE_SHIFT)
 
39
#define SLAP_CH_RESOLVE_CHAINING_PREFERRED              (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
 
40
#define SLAP_CH_RESOLVE_CHAINING_REQUIRED               (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
 
41
#define SLAP_CH_RESOLVE_REFERRALS_PREFERRED             (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
 
42
#define SLAP_CH_RESOLVE_REFERRALS_REQUIRED              (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
 
43
#define SLAP_CH_RESOLVE_DEFAULT                         (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
 
44
#define SLAP_CH_CONTINUATION_SHIFT                      (SLAP_CH_RESOLVE_SHIFT + 2)
 
45
#define SLAP_CH_CONTINUATION_MASK                       (0x3 << SLAP_CH_CONTINUATION_SHIFT)
 
46
#define SLAP_CH_CONTINUATION_CHAINING_PREFERRED         (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
 
47
#define SLAP_CH_CONTINUATION_CHAINING_REQUIRED          (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
 
48
#define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED        (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
 
49
#define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED         (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
 
50
#define SLAP_CH_CONTINUATION_DEFAULT                    (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
 
51
 
 
52
#define o_chaining                      o_ctrlflag[sc_chainingBehavior]
 
53
#define get_chaining(op)                ((op)->o_chaining & SLAP_CONTROL_MASK)
 
54
#define get_chainingBehavior(op)        ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
 
55
#define get_resolveBehavior(op)         ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
 
56
#define get_continuationBehavior(op)    ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
 
57
 
 
58
static int              sc_chainingBehavior;
 
59
#endif /*  LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
60
 
 
61
typedef enum {
 
62
        LDAP_CH_NONE = 0,
 
63
        LDAP_CH_RES,
 
64
        LDAP_CH_ERR
 
65
} ldap_chain_status_t;
 
66
static BackendInfo      *lback;
 
67
 
 
68
typedef struct ldap_chain_t {
 
69
        /*
 
70
         * A "template" ldapinfo_t gets all common configuration items;
 
71
         * then, for each configured URI, an entry is created in the tree;
 
72
         * all the specific configuration items get in the current URI 
 
73
         * structure.
 
74
         *
 
75
         * Then, for each referral, extract the URI and lookup the
 
76
         * related structure.  If configured to do so, allow URIs
 
77
         * not found in the structure to create a temporary one
 
78
         * that chains anonymously; maybe it can also be added to 
 
79
         * the tree?  Should be all configurable.
 
80
         */
 
81
 
 
82
        /* "common" configuration info (anything occurring before an "uri") */
 
83
        ldapinfo_t              *lc_common_li;
 
84
 
 
85
        /* current configuration info */
 
86
        ldapinfo_t              *lc_cfg_li;
 
87
 
 
88
        /* tree of configured[/generated?] "uri" info */
 
89
        ldap_avl_info_t         lc_lai;
 
90
 
 
91
        /* max depth in nested referrals chaining */
 
92
        int                     lc_max_depth;
 
93
 
 
94
        unsigned                lc_flags;
 
95
#define LDAP_CHAIN_F_NONE               (0x00U)
 
96
#define LDAP_CHAIN_F_CHAINING           (0x01U)
 
97
#define LDAP_CHAIN_F_CACHE_URI          (0x02U)
 
98
#define LDAP_CHAIN_F_RETURN_ERR         (0x04U)
 
99
 
 
100
#define LDAP_CHAIN_ISSET(lc, f)         ( ( (lc)->lc_flags & (f) ) == (f) )
 
101
#define LDAP_CHAIN_CHAINING( lc )       LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
 
102
#define LDAP_CHAIN_CACHE_URI( lc )      LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
 
103
#define LDAP_CHAIN_RETURN_ERR( lc )     LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
 
104
 
 
105
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
106
        LDAPControl             lc_chaining_ctrl;
 
107
        char                    lc_chaining_ctrlflag;
 
108
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
109
} ldap_chain_t;
 
110
 
 
111
static int ldap_chain_db_init_common( BackendDB *be );
 
112
static int ldap_chain_db_init_one( BackendDB *be );
 
113
static int ldap_chain_db_open_one( BackendDB *be );
 
114
#define ldap_chain_db_close_one(be)     (0)
 
115
#define ldap_chain_db_destroy_one(be, rs)       (lback)->bi_db_destroy( (be), (rs) )
 
116
 
 
117
typedef struct ldap_chain_cb_t {
 
118
        ldap_chain_status_t     lb_status;
 
119
        ldap_chain_t            *lb_lc;
 
120
        BI_op_func              *lb_op_f;
 
121
        int                     lb_depth;
 
122
} ldap_chain_cb_t;
 
123
 
 
124
static int
 
125
ldap_chain_op(
 
126
        Operation       *op,
 
127
        SlapReply       *rs,
 
128
        BI_op_func      *op_f,
 
129
        BerVarray       ref,
 
130
        int             depth );
 
131
 
 
132
static int
 
133
ldap_chain_search(
 
134
        Operation       *op,
 
135
        SlapReply       *rs,
 
136
        BerVarray       ref,
 
137
        int             depth );
 
138
 
 
139
static slap_overinst ldapchain;
 
140
 
 
141
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
142
static int
 
143
chaining_control_add(
 
144
                ldap_chain_t    *lc,
 
145
                Operation       *op, 
 
146
                LDAPControl     ***oldctrlsp )
 
147
{
 
148
        LDAPControl     **ctrls = NULL;
 
149
        int             c = 0;
 
150
 
 
151
        *oldctrlsp = op->o_ctrls;
 
152
 
 
153
        /* default chaining control not defined */
 
154
        if ( !LDAP_CHAIN_CHAINING( lc ) ) {
 
155
                return 0;
 
156
        }
 
157
 
 
158
        /* already present */
 
159
        if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
 
160
                return 0;
 
161
        }
 
162
 
 
163
        /* FIXME: check other incompatibilities */
 
164
 
 
165
        /* add to other controls */
 
166
        if ( op->o_ctrls ) {
 
167
                for ( c = 0; op->o_ctrls[ c ]; c++ )
 
168
                        /* count them */ ;
 
169
        }
 
170
 
 
171
        ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
 
172
        ctrls[ 0 ] = &lc->lc_chaining_ctrl;
 
173
        if ( op->o_ctrls ) {
 
174
                for ( c = 0; op->o_ctrls[ c ]; c++ ) {
 
175
                        ctrls[ c + 1 ] = op->o_ctrls[ c ];
 
176
                }
 
177
        }
 
178
        ctrls[ c + 1 ] = NULL;
 
179
 
 
180
        op->o_ctrls = ctrls;
 
181
 
 
182
        op->o_chaining = lc->lc_chaining_ctrlflag;
 
183
 
 
184
        return 0;
 
185
}
 
186
 
 
187
static int
 
188
chaining_control_remove(
 
189
                Operation       *op, 
 
190
                LDAPControl     ***oldctrlsp )
 
191
{
 
192
        LDAPControl     **oldctrls = *oldctrlsp;
 
193
 
 
194
        /* we assume that the first control is the chaining control
 
195
         * added by the chain overlay, so it's the only one we explicitly 
 
196
         * free */
 
197
        if ( op->o_ctrls != oldctrls ) {
 
198
                assert( op->o_ctrls != NULL );
 
199
                assert( op->o_ctrls[ 0 ] != NULL );
 
200
 
 
201
                free( op->o_ctrls );
 
202
 
 
203
                op->o_chaining = 0;
 
204
                op->o_ctrls = oldctrls;
 
205
        } 
 
206
 
 
207
        *oldctrlsp = NULL;
 
208
 
 
209
        return 0;
 
210
}
 
211
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
212
 
 
213
static int
 
214
ldap_chain_uri_cmp( const void *c1, const void *c2 )
 
215
{
 
216
        const ldapinfo_t        *li1 = (const ldapinfo_t *)c1;
 
217
        const ldapinfo_t        *li2 = (const ldapinfo_t *)c2;
 
218
 
 
219
        assert( li1->li_bvuri != NULL );
 
220
        assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
 
221
        assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
 
222
 
 
223
        assert( li2->li_bvuri != NULL );
 
224
        assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
 
225
        assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
 
226
 
 
227
        /* If local DNs don't match, it is definitely not a match */
 
228
        return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
 
229
}
 
230
 
 
231
static int
 
232
ldap_chain_uri_dup( void *c1, void *c2 )
 
233
{
 
234
        ldapinfo_t      *li1 = (ldapinfo_t *)c1;
 
235
        ldapinfo_t      *li2 = (ldapinfo_t *)c2;
 
236
 
 
237
        assert( li1->li_bvuri != NULL );
 
238
        assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
 
239
        assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
 
240
 
 
241
        assert( li2->li_bvuri != NULL );
 
242
        assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
 
243
        assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
 
244
 
 
245
        /* Cannot have more than one shared session with same DN */
 
246
        if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
 
247
                return -1;
 
248
        }
 
249
                
 
250
        return 0;
 
251
}
 
252
 
 
253
/*
 
254
 * Search specific response that strips entryDN from entries
 
255
 */
 
256
static int
 
257
ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
 
258
{
 
259
        ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
 
260
 
 
261
        assert( op->o_tag == LDAP_REQ_SEARCH );
 
262
 
 
263
        /* if in error, don't proceed any further */
 
264
        if ( lb->lb_status == LDAP_CH_ERR ) {
 
265
                return 0;
 
266
        }
 
267
 
 
268
        if ( rs->sr_type == REP_SEARCH ) {
 
269
                Attribute       **ap = &rs->sr_entry->e_attrs;
 
270
 
 
271
                for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
 
272
                        /* will be generated later by frontend
 
273
                         * (a cleaner solution would be that
 
274
                         * the frontend checks if it already exists */
 
275
                        if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
 
276
                        {
 
277
                                Attribute *a = *ap;
 
278
 
 
279
                                *ap = (*ap)->a_next;
 
280
                                attr_free( a );
 
281
 
 
282
                                /* there SHOULD be one only! */
 
283
                                break;
 
284
                        }
 
285
                }
 
286
 
 
287
                /* tell the frontend not to add generated
 
288
                 * operational attributes */
 
289
                rs->sr_flags |= REP_NO_OPERATIONALS;
 
290
                
 
291
                return SLAP_CB_CONTINUE;
 
292
 
 
293
        } else if ( rs->sr_type == REP_SEARCHREF ) {
 
294
                /* if we get it here, it means the library was unable
 
295
                 * to chase the referral... */
 
296
                if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
 
297
                        rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
 
298
                }
 
299
 
 
300
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
301
                if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
 
302
                        switch ( get_continuationBehavior( op ) ) {
 
303
                        case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
 
304
                                lb->lb_status = LDAP_CH_ERR;
 
305
                                return rs->sr_err = LDAP_X_CANNOT_CHAIN;
 
306
 
 
307
                        default:
 
308
                                break;
 
309
                        }
 
310
                }
 
311
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
312
                return SLAP_CB_CONTINUE;
 
313
 
 
314
        } else if ( rs->sr_type == REP_RESULT ) {
 
315
                if ( rs->sr_err == LDAP_REFERRAL
 
316
                        && lb->lb_depth < lb->lb_lc->lc_max_depth
 
317
                        && rs->sr_ref != NULL )
 
318
                {
 
319
                        rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
 
320
                }
 
321
 
 
322
                /* back-ldap tried to send result */
 
323
                lb->lb_status = LDAP_CH_RES;
 
324
        }
 
325
 
 
326
        return 0;
 
327
}
 
328
 
 
329
/*
 
330
 * Dummy response that simply traces if back-ldap tried to send 
 
331
 * anything to the client
 
332
 */
 
333
static int
 
334
ldap_chain_cb_response( Operation *op, SlapReply *rs )
 
335
{
 
336
        ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
 
337
 
 
338
        /* if in error, don't proceed any further */
 
339
        if ( lb->lb_status == LDAP_CH_ERR ) {
 
340
                return 0;
 
341
        }
 
342
 
 
343
        if ( rs->sr_type == REP_RESULT ) {
 
344
retry:;
 
345
                switch ( rs->sr_err ) {
 
346
                case LDAP_COMPARE_TRUE:
 
347
                case LDAP_COMPARE_FALSE:
 
348
                        if ( op->o_tag != LDAP_REQ_COMPARE ) {
 
349
                                return rs->sr_err;
 
350
                        }
 
351
                        /* fallthru */
 
352
 
 
353
                case LDAP_SUCCESS:
 
354
                        lb->lb_status = LDAP_CH_RES;
 
355
                        break;
 
356
 
 
357
                case LDAP_REFERRAL:
 
358
                        if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
 
359
                                rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
 
360
                                goto retry;
 
361
                        }
 
362
 
 
363
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
364
                        if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
 
365
                                switch ( get_continuationBehavior( op ) ) {
 
366
                                case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
 
367
                                        lb->lb_status = LDAP_CH_ERR;
 
368
                                        return rs->sr_err = LDAP_X_CANNOT_CHAIN;
 
369
 
 
370
                                default:
 
371
                                        break;
 
372
                                }
 
373
                        }
 
374
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
375
                        break;
 
376
 
 
377
                default:
 
378
                        return rs->sr_err;
 
379
                }
 
380
 
 
381
        } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
 
382
        {
 
383
                /* strip the entryDN attribute, but keep returning results */
 
384
                (void)ldap_chain_cb_search_response( op, rs );
 
385
        }
 
386
 
 
387
        return SLAP_CB_CONTINUE;
 
388
}
 
389
 
 
390
static int
 
391
ldap_chain_op(
 
392
        Operation       *op,
 
393
        SlapReply       *rs,
 
394
        BI_op_func      *op_f,
 
395
        BerVarray       ref,
 
396
        int             depth )
 
397
{
 
398
        slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
 
399
        ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
 
400
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
401
        ldapinfo_t      li = { 0 }, *lip = NULL;
 
402
        struct berval   bvuri[ 2 ] = { { 0 } };
 
403
 
 
404
        /* NOTE: returned if ref is empty... */
 
405
        int             rc = LDAP_OTHER,
 
406
                        first_rc;
 
407
 
 
408
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
409
        LDAPControl     **ctrls = NULL;
 
410
        
 
411
        (void)chaining_control_add( lc, op, &ctrls );
 
412
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
413
 
 
414
        li.li_bvuri = bvuri;
 
415
        first_rc = -1;
 
416
        for ( ; !BER_BVISNULL( ref ); ref++ ) {
 
417
                SlapReply       rs2 = { 0 };
 
418
                LDAPURLDesc     *srv = NULL;
 
419
                struct berval   save_req_dn = op->o_req_dn,
 
420
                                save_req_ndn = op->o_req_ndn,
 
421
                                dn = BER_BVNULL,
 
422
                                pdn = BER_BVNULL,
 
423
                                ndn = BER_BVNULL;
 
424
                int             temporary = 0;
 
425
                        
 
426
                /* We're setting the URI of the first referral;
 
427
                 * what if there are more?
 
428
 
 
429
Document: RFC 4511
 
430
 
 
431
4.1.10. Referral 
 
432
   ...
 
433
   If the client wishes to progress the operation, it MUST follow the 
 
434
   referral by contacting one of the supported services. If multiple 
 
435
   URIs are present, the client assumes that any supported URI may be 
 
436
   used to progress the operation. 
 
437
 
 
438
                 * so we actually need to follow exactly one,
 
439
                 * and we can assume any is fine.
 
440
                 */
 
441
        
 
442
                /* parse reference and use 
 
443
                 * proto://[host][:port]/ only */
 
444
                rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
 
445
                if ( rc != LDAP_URL_SUCCESS ) {
 
446
                        /* try next */
 
447
                        rc = LDAP_OTHER;
 
448
                        continue;
 
449
                }
 
450
 
 
451
                /* normalize DN */
 
452
                rc = LDAP_SUCCESS;
 
453
                srv->lud_scope = LDAP_SCOPE_DEFAULT;
 
454
                if ( srv->lud_dn != NULL ) {
 
455
                        ber_str2bv( srv->lud_dn, 0, 0, &dn );
 
456
                        rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
 
457
                        if ( rc == LDAP_SUCCESS ) {
 
458
                                /* remove DN essentially because later on 
 
459
                                 * ldap_initialize() will parse the URL 
 
460
                                 * as a comma-separated URL list */
 
461
                                srv->lud_dn = "";
 
462
                        }
 
463
 
 
464
                } else {
 
465
                        srv->lud_dn = "";
 
466
                }
 
467
 
 
468
                li.li_uri = ldap_url_desc2str( srv );
 
469
                srv->lud_dn = dn.bv_val;
 
470
                ldap_free_urldesc( srv );
 
471
 
 
472
                if ( rc != LDAP_SUCCESS ) {
 
473
                        /* try next */
 
474
                        rc = LDAP_OTHER;
 
475
                        continue;
 
476
                }
 
477
 
 
478
                if ( li.li_uri == NULL ) {
 
479
                        /* try next */
 
480
                        rc = LDAP_OTHER;
 
481
                        goto further_cleanup;
 
482
                }
 
483
 
 
484
                op->o_req_dn = pdn;
 
485
                op->o_req_ndn = ndn;
 
486
 
 
487
                ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
 
488
 
 
489
                /* Searches for a ldapinfo in the avl tree */
 
490
                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
 
491
                lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 
 
492
                        (caddr_t)&li, ldap_chain_uri_cmp );
 
493
                ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
494
 
 
495
                if ( lip != NULL ) {
 
496
                        op->o_bd->be_private = (void *)lip;
 
497
 
 
498
                } else {
 
499
                        rc = ldap_chain_db_init_one( op->o_bd );
 
500
                        if ( rc != 0 ) {
 
501
                                goto cleanup;
 
502
                        }
 
503
                        lip = (ldapinfo_t *)op->o_bd->be_private;
 
504
                        lip->li_uri = li.li_uri;
 
505
                        lip->li_bvuri = bvuri;
 
506
                        rc = ldap_chain_db_open_one( op->o_bd );
 
507
                        if ( rc != 0 ) {
 
508
                                lip->li_uri = NULL;
 
509
                                lip->li_bvuri = NULL;
 
510
                                (void)ldap_chain_db_destroy_one( op->o_bd, NULL);
 
511
                                goto cleanup;
 
512
                        }
 
513
 
 
514
                        if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
 
515
                                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
 
516
                                if ( avl_insert( &lc->lc_lai.lai_tree,
 
517
                                        (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
 
518
                                {
 
519
                                        /* someone just inserted another;
 
520
                                         * don't bother, use this and then
 
521
                                         * just free it */
 
522
                                        temporary = 1;
 
523
                                }
 
524
                                ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
525
 
 
526
                        } else {
 
527
                                temporary = 1;
 
528
                        }
 
529
                }
 
530
 
 
531
                lb->lb_op_f = op_f;
 
532
                lb->lb_depth = depth + 1;
 
533
 
 
534
                rc = op_f( op, &rs2 );
 
535
 
 
536
                /* note the first error */
 
537
                if ( first_rc == -1 ) {
 
538
                        first_rc = rc;
 
539
                }
 
540
 
 
541
cleanup:;
 
542
                ldap_memfree( li.li_uri );
 
543
                li.li_uri = NULL;
 
544
 
 
545
                if ( temporary ) {
 
546
                        lip->li_uri = NULL;
 
547
                        lip->li_bvuri = NULL;
 
548
                        (void)ldap_chain_db_close_one( op->o_bd );
 
549
                        (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
 
550
                }
 
551
 
 
552
further_cleanup:;
 
553
                if ( !BER_BVISNULL( &pdn ) ) {
 
554
                        op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
 
555
                }
 
556
                op->o_req_dn = save_req_dn;
 
557
 
 
558
                if ( !BER_BVISNULL( &ndn ) ) {
 
559
                        op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
 
560
                }
 
561
                op->o_req_ndn = save_req_ndn;
 
562
                
 
563
                if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
 
564
                        *rs = rs2;
 
565
                        break;
 
566
                }
 
567
 
 
568
                rc = rs2.sr_err;
 
569
        }
 
570
 
 
571
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
572
        (void)chaining_control_remove( op, &ctrls );
 
573
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
574
 
 
575
        if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
 
576
                rc = first_rc;
 
577
        }
 
578
 
 
579
        return rc;
 
580
}
 
581
 
 
582
static int
 
583
ldap_chain_search(
 
584
        Operation       *op,
 
585
        SlapReply       *rs,
 
586
        BerVarray       ref,
 
587
        int             depth )
 
588
 
 
589
{
 
590
        slap_overinst   *on = (slap_overinst *) op->o_bd->bd_info;
 
591
        ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
 
592
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
593
        ldapinfo_t      li = { 0 }, *lip = NULL;
 
594
        struct berval   bvuri[ 2 ] = { { 0 } };
 
595
 
 
596
        struct berval   odn = op->o_req_dn,
 
597
                        ondn = op->o_req_ndn;
 
598
        slap_response   *save_response = op->o_callback->sc_response;
 
599
 
 
600
        int             rc = LDAP_OTHER,
 
601
                        first_rc = -1;
 
602
 
 
603
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
604
        LDAPControl     **ctrls = NULL;
 
605
        
 
606
        (void)chaining_control_add( lc, op, &ctrls );
 
607
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
608
 
 
609
        rs->sr_type = REP_SEARCH;
 
610
 
 
611
        op->o_callback->sc_response = ldap_chain_cb_search_response;
 
612
 
 
613
        /* if we parse the URI then by no means 
 
614
         * we can cache stuff or reuse connections, 
 
615
         * because in back-ldap there's no caching
 
616
         * based on the URI value, which is supposed
 
617
         * to be set once for all (correct?) */
 
618
        li.li_bvuri = bvuri;
 
619
        for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
 
620
                SlapReply       rs2 = { 0 };
 
621
                LDAPURLDesc     *srv;
 
622
                struct berval   save_req_dn = op->o_req_dn,
 
623
                                save_req_ndn = op->o_req_ndn,
 
624
                                dn,
 
625
                                pdn = BER_BVNULL,
 
626
                                ndn = BER_BVNULL;
 
627
                int             temporary = 0;
 
628
 
 
629
                /* parse reference and use
 
630
                 * proto://[host][:port]/ only */
 
631
                rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
 
632
                if ( rc != LDAP_URL_SUCCESS ) {
 
633
                        /* try next */
 
634
                        rs->sr_err = LDAP_OTHER;
 
635
                        continue;
 
636
                }
 
637
 
 
638
                /* normalize DN */
 
639
                rc = LDAP_INVALID_SYNTAX;
 
640
                if ( srv->lud_dn != NULL ) {
 
641
                        ber_str2bv( srv->lud_dn, 0, 0, &dn );
 
642
                        rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
 
643
                        if ( rc == LDAP_SUCCESS ) {
 
644
                                /* remove DN essentially because later on 
 
645
                                 * ldap_initialize() will parse the URL 
 
646
                                 * as a comma-separated URL list */
 
647
                                srv->lud_dn = "";
 
648
                                srv->lud_scope = LDAP_SCOPE_DEFAULT;
 
649
                                li.li_uri = ldap_url_desc2str( srv );
 
650
                                srv->lud_dn = dn.bv_val;
 
651
                        }
 
652
                }
 
653
                ldap_free_urldesc( srv );
 
654
 
 
655
                if ( rc != LDAP_SUCCESS ) {
 
656
                        /* try next */
 
657
                        rc = LDAP_OTHER;
 
658
                        continue;
 
659
                }
 
660
 
 
661
                if ( li.li_uri == NULL ) {
 
662
                        /* try next */
 
663
                        rc = LDAP_OTHER;
 
664
                        goto further_cleanup;
 
665
                }
 
666
 
 
667
                op->o_req_dn = pdn;
 
668
                op->o_req_ndn = ndn;
 
669
 
 
670
                ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
 
671
 
 
672
                /* Searches for a ldapinfo in the avl tree */
 
673
                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
 
674
                lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree, 
 
675
                        (caddr_t)&li, ldap_chain_uri_cmp );
 
676
                ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
677
 
 
678
                if ( lip != NULL ) {
 
679
                        op->o_bd->be_private = (void *)lip;
 
680
 
 
681
                } else {
 
682
                        /* if none is found, create a temporary... */
 
683
                        rc = ldap_chain_db_init_one( op->o_bd );
 
684
                        if ( rc != 0 ) {
 
685
                                goto cleanup;
 
686
                        }
 
687
                        lip = (ldapinfo_t *)op->o_bd->be_private;
 
688
                        lip->li_uri = li.li_uri;
 
689
                        lip->li_bvuri = bvuri;
 
690
                        rc = ldap_chain_db_open_one( op->o_bd );
 
691
                        if ( rc != 0 ) {
 
692
                                lip->li_uri = NULL;
 
693
                                lip->li_bvuri = NULL;
 
694
                                (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
 
695
                                goto cleanup;
 
696
                        }
 
697
 
 
698
                        if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
 
699
                                ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
 
700
                                if ( avl_insert( &lc->lc_lai.lai_tree,
 
701
                                        (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
 
702
                                {
 
703
                                        /* someone just inserted another;
 
704
                                         * don't bother, use this and then
 
705
                                         * just free it */
 
706
                                        temporary = 1;
 
707
                                }
 
708
                                ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
709
 
 
710
                        } else {
 
711
                                temporary = 1;
 
712
                        }
 
713
                }
 
714
 
 
715
                lb->lb_op_f = lback->bi_op_search;
 
716
                lb->lb_depth = depth + 1;
 
717
 
 
718
                /* FIXME: should we also copy filter and scope?
 
719
                 * according to RFC3296, no */
 
720
                rc = lback->bi_op_search( op, &rs2 );
 
721
                if ( first_rc == -1 ) {
 
722
                        first_rc = rc;
 
723
                }
 
724
 
 
725
cleanup:;
 
726
                ldap_memfree( li.li_uri );
 
727
                li.li_uri = NULL;
 
728
 
 
729
                if ( temporary ) {
 
730
                        lip->li_uri = NULL;
 
731
                        lip->li_bvuri = NULL;
 
732
                        (void)ldap_chain_db_close_one( op->o_bd );
 
733
                        (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
 
734
                }
 
735
                
 
736
further_cleanup:;
 
737
                if ( !BER_BVISNULL( &pdn ) ) {
 
738
                        op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
 
739
                }
 
740
                op->o_req_dn = save_req_dn;
 
741
 
 
742
                if ( !BER_BVISNULL( &ndn ) ) {
 
743
                        op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
 
744
                }
 
745
                op->o_req_ndn = save_req_ndn;
 
746
                
 
747
                if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
 
748
                        *rs = rs2;
 
749
                        break;
 
750
                }
 
751
 
 
752
                rc = rs2.sr_err;
 
753
        }
 
754
 
 
755
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
756
        (void)chaining_control_remove( op, &ctrls );
 
757
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
758
 
 
759
        op->o_req_dn = odn;
 
760
        op->o_req_ndn = ondn;
 
761
        op->o_callback->sc_response = save_response;
 
762
        rs->sr_type = REP_SEARCHREF;
 
763
        rs->sr_entry = NULL;
 
764
 
 
765
        if ( rc != LDAP_SUCCESS ) {
 
766
                /* couldn't chase any of the referrals */
 
767
                if ( first_rc != -1 ) {
 
768
                        rc = first_rc;
 
769
 
 
770
                } else {
 
771
                        rc = SLAP_CB_CONTINUE;
 
772
                }
 
773
        }
 
774
 
 
775
        return rc;
 
776
}
 
777
 
 
778
static int
 
779
ldap_chain_response( Operation *op, SlapReply *rs )
 
780
{
 
781
        slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
 
782
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
783
        BackendDB       db, *bd = op->o_bd;
 
784
        ldap_chain_cb_t lb = { 0 };
 
785
        slap_callback   *sc = op->o_callback,
 
786
                        sc2 = { 0 };
 
787
        int             rc = 0;
 
788
        const char      *text = NULL;
 
789
        const char      *matched;
 
790
        BerVarray       ref;
 
791
        struct berval   ndn = op->o_ndn;
 
792
 
 
793
        int             sr_err = rs->sr_err;
 
794
        slap_reply_t    sr_type = rs->sr_type;
 
795
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
796
        slap_mask_t     chain_mask = 0;
 
797
        ber_len_t       chain_shift = 0;
 
798
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
799
 
 
800
        if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
 
801
                return SLAP_CB_CONTINUE;
 
802
        }
 
803
 
 
804
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
805
        if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
 
806
                switch ( get_resolveBehavior( op ) ) {
 
807
                case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
 
808
                case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
 
809
                        return SLAP_CB_CONTINUE;
 
810
 
 
811
                default:
 
812
                        chain_mask = SLAP_CH_RESOLVE_MASK;
 
813
                        chain_shift = SLAP_CH_RESOLVE_SHIFT;
 
814
                        break;
 
815
                }
 
816
 
 
817
        } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
 
818
                switch ( get_continuationBehavior( op ) ) {
 
819
                case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
 
820
                case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
 
821
                        return SLAP_CB_CONTINUE;
 
822
 
 
823
                default:
 
824
                        chain_mask = SLAP_CH_CONTINUATION_MASK;
 
825
                        chain_shift = SLAP_CH_CONTINUATION_SHIFT;
 
826
                        break;
 
827
                }
 
828
        }
 
829
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
830
 
 
831
        /*
 
832
         * TODO: add checks on who/when chain operations; e.g.:
 
833
         *   a) what identities are authorized
 
834
         *   b) what request DN (e.g. only chain requests rooted at <DN>)
 
835
         *   c) what referral URIs
 
836
         *   d) what protocol scheme (e.g. only ldaps://)
 
837
         *   e) what ssf
 
838
         */
 
839
 
 
840
        db = *op->o_bd;
 
841
        SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
 
842
        op->o_bd = &db;
 
843
 
 
844
        text = rs->sr_text;
 
845
        rs->sr_text = NULL;
 
846
        matched = rs->sr_matched;
 
847
        rs->sr_matched = NULL;
 
848
        ref = rs->sr_ref;
 
849
        rs->sr_ref = NULL;
 
850
 
 
851
        /* we need this to know if back-ldap returned any result */
 
852
        lb.lb_lc = lc;
 
853
        sc2.sc_private = &lb;
 
854
        sc2.sc_response = ldap_chain_cb_response;
 
855
        op->o_callback = &sc2;
 
856
 
 
857
        /* Chaining can be performed by a privileged user on behalf
 
858
         * of normal users, using the ProxyAuthz control, by exploiting
 
859
         * the identity assertion feature of back-ldap; see idassert-*
 
860
         * directives in slapd-ldap(5).
 
861
         *
 
862
         * FIXME: the idassert-authcDN is one, will it be fine regardless
 
863
         * of the URI we obtain from the referral?
 
864
         */
 
865
 
 
866
        switch ( op->o_tag ) {
 
867
        case LDAP_REQ_BIND: {
 
868
                struct berval   rndn = op->o_req_ndn;
 
869
                Connection      *conn = op->o_conn;
 
870
 
 
871
                /* FIXME: can we really get a referral for binds? */
 
872
                op->o_req_ndn = slap_empty_bv;
 
873
                op->o_conn = NULL;
 
874
                rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
 
875
                op->o_req_ndn = rndn;
 
876
                op->o_conn = conn;
 
877
                }
 
878
                break;
 
879
 
 
880
        case LDAP_REQ_ADD:
 
881
                rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
 
882
                break;
 
883
 
 
884
        case LDAP_REQ_DELETE:
 
885
                rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
 
886
                break;
 
887
 
 
888
        case LDAP_REQ_MODRDN:
 
889
                rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
 
890
                break;
 
891
 
 
892
        case LDAP_REQ_MODIFY:
 
893
                rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
 
894
                break;
 
895
 
 
896
        case LDAP_REQ_COMPARE:
 
897
                rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
 
898
                if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
 
899
                        rc = LDAP_SUCCESS;
 
900
                }
 
901
                break;
 
902
 
 
903
        case LDAP_REQ_SEARCH:
 
904
                if ( rs->sr_type == REP_SEARCHREF ) {
 
905
                        rc = ldap_chain_search( op, rs, ref, 0 );
 
906
                        
 
907
                } else {
 
908
                        /* we might get here before any database actually 
 
909
                         * performed a search; in those cases, we need
 
910
                         * to check limits, to make sure safe defaults
 
911
                         * are in place */
 
912
                        if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
 
913
                                rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
 
914
 
 
915
                        } else {
 
916
                                rc = SLAP_CB_CONTINUE;
 
917
                        }
 
918
                }
 
919
                break;
 
920
 
 
921
        case LDAP_REQ_EXTENDED:
 
922
                rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
 
923
                /* FIXME: ldap_back_extended() by design 
 
924
                 * doesn't send result; frontend is expected
 
925
                 * to send it... */
 
926
                /* FIXME: what about chaining? */
 
927
                if ( rc != SLAPD_ABANDON ) {
 
928
                        rs->sr_err = rc;
 
929
                        send_ldap_extended( op, rs );
 
930
                        rc = LDAP_SUCCESS;
 
931
                }
 
932
                lb.lb_status = LDAP_CH_RES;
 
933
                break;
 
934
 
 
935
        default:
 
936
                rc = SLAP_CB_CONTINUE;
 
937
                break;
 
938
        }
 
939
 
 
940
        switch ( rc ) {
 
941
        case SLAPD_ABANDON:
 
942
                goto dont_chain;
 
943
 
 
944
        case LDAP_SUCCESS:
 
945
        case LDAP_REFERRAL:
 
946
                /* slapd-ldap sent response */
 
947
                if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
 
948
                        /* FIXME: should we send response? */
 
949
                        Debug( LDAP_DEBUG_ANY,
 
950
                                "%s: ldap_chain_response: "
 
951
                                "overlay should have sent result.\n",
 
952
                                op->o_log_prefix, 0, 0 );
 
953
                }
 
954
                break;
 
955
 
 
956
        default:
 
957
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
958
                if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
 
959
                        goto cannot_chain;
 
960
                }
 
961
 
 
962
                switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
 
963
                case LDAP_CHAINING_REQUIRED:
 
964
cannot_chain:;
 
965
                        op->o_callback = NULL;
 
966
                        send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
 
967
                                "operation cannot be completed without chaining" );
 
968
                        goto dont_chain;
 
969
 
 
970
                default:
 
971
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
972
                        if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
 
973
                                rs->sr_err = rc;
 
974
                                rs->sr_type = sr_type;
 
975
 
 
976
                        } else {
 
977
                                rc = SLAP_CB_CONTINUE;
 
978
                                rs->sr_err = sr_err;
 
979
                                rs->sr_type = sr_type;
 
980
                                rs->sr_text = text;
 
981
                                rs->sr_matched = matched;
 
982
                                rs->sr_ref = ref;
 
983
                        }
 
984
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
985
                        break;
 
986
                }
 
987
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
988
        }
 
989
 
 
990
        if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
 
991
                op->o_callback = NULL;
 
992
                rc = rs->sr_err = slap_map_api2result( rs );
 
993
                send_ldap_result( op, rs );
 
994
        }
 
995
 
 
996
dont_chain:;
 
997
        rs->sr_err = sr_err;
 
998
        rs->sr_type = sr_type;
 
999
        rs->sr_text = text;
 
1000
        rs->sr_matched = matched;
 
1001
        rs->sr_ref = ref;
 
1002
        op->o_bd = bd;
 
1003
        op->o_callback = sc;
 
1004
        op->o_ndn = ndn;
 
1005
 
 
1006
        return rc;
 
1007
}
 
1008
 
 
1009
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1010
static int
 
1011
ldap_chain_parse_ctrl(
 
1012
        Operation       *op,
 
1013
        SlapReply       *rs,
 
1014
        LDAPControl     *ctrl );
 
1015
 
 
1016
static int
 
1017
str2chain( const char *s )
 
1018
{
 
1019
        if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
 
1020
                return LDAP_CHAINING_PREFERRED;
 
1021
                
 
1022
        } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
 
1023
                return LDAP_CHAINING_REQUIRED;
 
1024
 
 
1025
        } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
 
1026
                return LDAP_REFERRALS_PREFERRED;
 
1027
                
 
1028
        } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
 
1029
                return LDAP_REFERRALS_REQUIRED;
 
1030
        }
 
1031
 
 
1032
        return -1;
 
1033
}
 
1034
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1035
 
 
1036
/*
 
1037
 * configuration...
 
1038
 */
 
1039
 
 
1040
enum {
 
1041
        CH_CHAINING = 1,
 
1042
        CH_CACHE_URI,
 
1043
        CH_MAX_DEPTH,
 
1044
        CH_RETURN_ERR,
 
1045
 
 
1046
        CH_LAST
 
1047
};
 
1048
 
 
1049
static ConfigDriver chain_cf_gen;
 
1050
static ConfigCfAdd chain_cfadd;
 
1051
static ConfigLDAPadd chain_ldadd;
 
1052
 
 
1053
static ConfigTable chaincfg[] = {
 
1054
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1055
        { "chain-chaining", "args",
 
1056
                2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
 
1057
                "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
 
1058
                        "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
 
1059
                        "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
 
1060
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1061
        { "chain-cache-uri", "TRUE/FALSE",
 
1062
                2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
 
1063
                "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
 
1064
                        "DESC 'Enables caching of URIs not present in configuration' "
 
1065
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
 
1066
        { "chain-max-depth", "args",
 
1067
                2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
 
1068
                "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
 
1069
                        "DESC 'max referral depth' "
 
1070
                        "SYNTAX OMsInteger "
 
1071
                        "EQUALITY integerMatch "
 
1072
                        "SINGLE-VALUE )", NULL, NULL },
 
1073
        { "chain-return-error", "TRUE/FALSE",
 
1074
                2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
 
1075
                "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
 
1076
                        "DESC 'Errors are returned instead of the original referral' "
 
1077
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
 
1078
        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
 
1079
};
 
1080
 
 
1081
static ConfigOCs chainocs[] = {
 
1082
        { "( OLcfgOvOc:3.1 "
 
1083
                "NAME 'olcChainConfig' "
 
1084
                "DESC 'Chain configuration' "
 
1085
                "SUP olcOverlayConfig "
 
1086
                "MAY ( "
 
1087
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1088
                        "olcChainingBehavior $ "
 
1089
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1090
                        "olcChainCacheURI $ "
 
1091
                        "olcChainMaxReferralDepth $ "
 
1092
                        "olcChainReturnError "
 
1093
                        ") )",
 
1094
                Cft_Overlay, chaincfg, NULL, chain_cfadd },
 
1095
        { "( OLcfgOvOc:3.2 "
 
1096
                "NAME 'olcChainDatabase' "
 
1097
                "DESC 'Chain remote server configuration' "
 
1098
                "AUXILIARY )",
 
1099
                Cft_Misc, chaincfg, chain_ldadd },
 
1100
        { NULL, 0, NULL }
 
1101
};
 
1102
 
 
1103
static int
 
1104
chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
 
1105
{
 
1106
        slap_overinst           *on;
 
1107
        ldap_chain_t            *lc;
 
1108
 
 
1109
        ldapinfo_t              *li;
 
1110
 
 
1111
        AttributeDescription    *ad = NULL;
 
1112
        Attribute               *at;
 
1113
        const char              *text;
 
1114
 
 
1115
        int                     rc;
 
1116
 
 
1117
        if ( p->ce_type != Cft_Overlay
 
1118
                || !p->ce_bi
 
1119
                || p->ce_bi->bi_cf_ocs != chainocs )
 
1120
        {
 
1121
                return LDAP_CONSTRAINT_VIOLATION;
 
1122
        }
 
1123
 
 
1124
        on = (slap_overinst *)p->ce_bi;
 
1125
        lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1126
 
 
1127
        assert( ca->be == NULL );
 
1128
        ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
 
1129
 
 
1130
        ca->be->bd_info = (BackendInfo *)on;
 
1131
 
 
1132
        rc = slap_str2ad( "olcDbURI", &ad, &text );
 
1133
        assert( rc == LDAP_SUCCESS );
 
1134
 
 
1135
        at = attr_find( e->e_attrs, ad );
 
1136
        if ( lc->lc_common_li == NULL && at != NULL ) {
 
1137
                /* FIXME: we should generate an empty default entry
 
1138
                 * if none is supplied */
 
1139
                Debug( LDAP_DEBUG_ANY, "slapd-chain: "
 
1140
                        "first underlying database \"%s\" "
 
1141
                        "cannot contain attribute \"%s\".\n",
 
1142
                        e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
 
1143
                rc = LDAP_CONSTRAINT_VIOLATION;
 
1144
                goto done;
 
1145
 
 
1146
        } else if ( lc->lc_common_li != NULL && at == NULL ) {
 
1147
                /* FIXME: we should generate an empty default entry
 
1148
                 * if none is supplied */
 
1149
                Debug( LDAP_DEBUG_ANY, "slapd-chain: "
 
1150
                        "subsequent underlying database \"%s\" "
 
1151
                        "must contain attribute \"%s\".\n",
 
1152
                        e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
 
1153
                rc = LDAP_CONSTRAINT_VIOLATION;
 
1154
                goto done;
 
1155
        }
 
1156
 
 
1157
        if ( lc->lc_common_li == NULL ) {
 
1158
                rc = ldap_chain_db_init_common( ca->be );
 
1159
 
 
1160
        } else {
 
1161
                rc = ldap_chain_db_init_one( ca->be );
 
1162
        }
 
1163
 
 
1164
        if ( rc != 0 ) {
 
1165
                Debug( LDAP_DEBUG_ANY, "slapd-chain: "
 
1166
                        "unable to init %sunderlying database \"%s\".\n",
 
1167
                        lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
 
1168
                return LDAP_CONSTRAINT_VIOLATION;
 
1169
        }
 
1170
 
 
1171
        li = ca->be->be_private;
 
1172
 
 
1173
        if ( lc->lc_common_li == NULL ) {
 
1174
                lc->lc_common_li = li;
 
1175
 
 
1176
        } else {
 
1177
                li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
 
1178
                value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
 
1179
                if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
 
1180
                        ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
 
1181
                {
 
1182
                        Debug( LDAP_DEBUG_ANY, "slapd-chain: "
 
1183
                                "database \"%s\" insert failed.\n",
 
1184
                                e->e_name.bv_val, 0, 0 );
 
1185
                        rc = LDAP_CONSTRAINT_VIOLATION;
 
1186
                        goto done;
 
1187
                }
 
1188
        }
 
1189
 
 
1190
done:;
 
1191
        if ( rc != LDAP_SUCCESS ) {
 
1192
                (void)ldap_chain_db_destroy_one( ca->be, NULL );
 
1193
                ch_free( ca->be );
 
1194
                ca->be = NULL;
 
1195
        }
 
1196
 
 
1197
        return rc;
 
1198
}
 
1199
 
 
1200
typedef struct ldap_chain_cfadd_apply_t {
 
1201
        Operation       *op;
 
1202
        SlapReply       *rs;
 
1203
        Entry           *p;
 
1204
        ConfigArgs      *ca;
 
1205
        int             count;
 
1206
} ldap_chain_cfadd_apply_t;
 
1207
 
 
1208
static int
 
1209
ldap_chain_cfadd_apply( void *datum, void *arg )
 
1210
{
 
1211
        ldapinfo_t                      *li = (ldapinfo_t *)datum;
 
1212
        ldap_chain_cfadd_apply_t        *lca = (ldap_chain_cfadd_apply_t *)arg;
 
1213
 
 
1214
        struct berval                   bv;
 
1215
 
 
1216
        /* FIXME: should not hardcode "olcDatabase" here */
 
1217
        bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
 
1218
                "olcDatabase={%d}%s", lca->count, lback->bi_type );
 
1219
        bv.bv_val = lca->ca->cr_msg;
 
1220
 
 
1221
        lca->ca->be->be_private = (void *)li;
 
1222
        config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
 
1223
                &bv, lback->bi_cf_ocs, &chainocs[1] );
 
1224
 
 
1225
        lca->count++;
 
1226
 
 
1227
        return 0;
 
1228
}
 
1229
 
 
1230
static int
 
1231
chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
 
1232
{
 
1233
        CfEntryInfo     *pe = p->e_private;
 
1234
        slap_overinst   *on = (slap_overinst *)pe->ce_bi;
 
1235
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1236
        void            *priv = (void *)ca->be->be_private;
 
1237
 
 
1238
        if ( lback->bi_cf_ocs ) {
 
1239
                ldap_chain_cfadd_apply_t        lca = { 0 };
 
1240
 
 
1241
                lca.op = op;
 
1242
                lca.rs = rs;
 
1243
                lca.p = p;
 
1244
                lca.ca = ca;
 
1245
                lca.count = 0;
 
1246
 
 
1247
                (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
 
1248
 
 
1249
                (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
 
1250
                        &lca, 1, AVL_INORDER );
 
1251
 
 
1252
                ca->be->be_private = priv;
 
1253
        }
 
1254
 
 
1255
        return 0;
 
1256
}
 
1257
 
 
1258
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1259
static slap_verbmasks chaining_mode[] = {
 
1260
        { BER_BVC("referralsRequired"),         LDAP_REFERRALS_REQUIRED },
 
1261
        { BER_BVC("referralsPreferred"),        LDAP_REFERRALS_PREFERRED },
 
1262
        { BER_BVC("chainingRequired"),          LDAP_CHAINING_REQUIRED },
 
1263
        { BER_BVC("chainingPreferred"),         LDAP_CHAINING_PREFERRED },
 
1264
        { BER_BVNULL,                           0 }
 
1265
};
 
1266
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1267
 
 
1268
static int
 
1269
chain_cf_gen( ConfigArgs *c )
 
1270
{
 
1271
        slap_overinst   *on = (slap_overinst *)c->bi;
 
1272
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1273
 
 
1274
        int             rc = 0;
 
1275
 
 
1276
        if ( c->op == SLAP_CONFIG_EMIT ) {
 
1277
                switch( c->type ) {
 
1278
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1279
                case CH_CHAINING: {
 
1280
                        struct berval   resolve = BER_BVNULL,
 
1281
                                        continuation = BER_BVNULL;
 
1282
 
 
1283
                        if ( !LDAP_CHAIN_CHAINING( lc ) ) {
 
1284
                                return 1;
 
1285
                        }
 
1286
 
 
1287
                        enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
 
1288
                        enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
 
1289
 
 
1290
                        c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
 
1291
                                + STRLENOF( " " )
 
1292
                                + STRLENOF( "continuation=" ) + continuation.bv_len;
 
1293
                        c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
 
1294
                        snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
 
1295
                                "resolve=%s continuation=%s",
 
1296
                                resolve.bv_val, continuation.bv_val );
 
1297
 
 
1298
                        if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
 
1299
                                c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
 
1300
                                        c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
 
1301
                                AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
 
1302
                                        " critical", STRLENOF( " critical" ) + 1 );
 
1303
                                c->value_bv.bv_len += STRLENOF( " critical" );
 
1304
                        }
 
1305
 
 
1306
                        break;
 
1307
                }
 
1308
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1309
 
 
1310
                case CH_CACHE_URI:
 
1311
                        c->value_int = LDAP_CHAIN_CACHE_URI( lc );
 
1312
                        break;
 
1313
 
 
1314
                case CH_MAX_DEPTH:
 
1315
                        c->value_int = lc->lc_max_depth;
 
1316
                        break;
 
1317
 
 
1318
                case CH_RETURN_ERR:
 
1319
                        c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
 
1320
                        break;
 
1321
 
 
1322
                default:
 
1323
                        assert( 0 );
 
1324
                        rc = 1;
 
1325
                }
 
1326
                return rc;
 
1327
 
 
1328
        } else if ( c->op == LDAP_MOD_DELETE ) {
 
1329
                switch( c->type ) {
 
1330
                case CH_CHAINING:
 
1331
                        return 1;
 
1332
 
 
1333
                case CH_CACHE_URI:
 
1334
                        lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
 
1335
                        break;
 
1336
 
 
1337
                case CH_MAX_DEPTH:
 
1338
                        c->value_int = 0;
 
1339
                        break;
 
1340
 
 
1341
                case CH_RETURN_ERR:
 
1342
                        lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
 
1343
                        break;
 
1344
 
 
1345
                default:
 
1346
                        return 1;
 
1347
                }
 
1348
                return rc;
 
1349
        }
 
1350
 
 
1351
        switch( c->type ) {
 
1352
        case CH_CHAINING: {
 
1353
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1354
                char                    **argv = c->argv;
 
1355
                int                     argc = c->argc;
 
1356
                BerElementBuffer        berbuf;
 
1357
                BerElement              *ber = (BerElement *)&berbuf;
 
1358
                int                     resolve = -1,
 
1359
                                        continuation = -1,
 
1360
                                        iscritical = 0;
 
1361
                Operation               op = { 0 };
 
1362
                SlapReply               rs = { 0 };
 
1363
 
 
1364
                lc->lc_chaining_ctrlflag = 0;
 
1365
 
 
1366
                for ( argc--, argv++; argc > 0; argc--, argv++ ) {
 
1367
                        if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
 
1368
                                resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
 
1369
                                if ( resolve == -1 ) {
 
1370
                                        Debug( LDAP_DEBUG_ANY, "%s: "
 
1371
                                                "illegal <resolve> value %s "
 
1372
                                                "in \"chain-chaining>\".\n",
 
1373
                                                c->log, argv[ 0 ], 0 );
 
1374
                                        return 1;
 
1375
                                }
 
1376
 
 
1377
                        } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
 
1378
                                continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
 
1379
                                if ( continuation == -1 ) {
 
1380
                                        Debug( LDAP_DEBUG_ANY, "%s: "
 
1381
                                                "illegal <continuation> value %s "
 
1382
                                                "in \"chain-chaining\".\n",
 
1383
                                                c->log, argv[ 0 ], 0 );
 
1384
                                        return 1;
 
1385
                                }
 
1386
 
 
1387
                        } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
 
1388
                                iscritical = 1;
 
1389
 
 
1390
                        } else {
 
1391
                                Debug( LDAP_DEBUG_ANY, "%s: "
 
1392
                                        "unknown option in \"chain-chaining\".\n",
 
1393
                                        c->log, 0, 0 );
 
1394
                                return 1;
 
1395
                        }
 
1396
                }
 
1397
 
 
1398
                if ( resolve != -1 || continuation != -1 ) {
 
1399
                        int     err;
 
1400
 
 
1401
                        if ( resolve == -1 ) {
 
1402
                                /* default */
 
1403
                                resolve = SLAP_CHAINING_DEFAULT;
 
1404
                        }
 
1405
 
 
1406
                        ber_init2( ber, NULL, LBER_USE_DER );
 
1407
 
 
1408
                        err = ber_printf( ber, "{e" /* } */, resolve );
 
1409
                        if ( err == -1 ) {
 
1410
                                ber_free( ber, 1 );
 
1411
                                Debug( LDAP_DEBUG_ANY, "%s: "
 
1412
                                        "chaining behavior control encoding error!\n",
 
1413
                                        c->log, 0, 0 );
 
1414
                                return 1;
 
1415
                        }
 
1416
 
 
1417
                        if ( continuation > -1 ) {
 
1418
                                err = ber_printf( ber, "e", continuation );
 
1419
                                if ( err == -1 ) {
 
1420
                                        ber_free( ber, 1 );
 
1421
                                        Debug( LDAP_DEBUG_ANY, "%s: "
 
1422
                                                "chaining behavior control encoding error!\n",
 
1423
                                                c->log, 0, 0 );
 
1424
                                        return 1;
 
1425
                                }
 
1426
                        }
 
1427
 
 
1428
                        err = ber_printf( ber, /* { */ "N}" );
 
1429
                        if ( err == -1 ) {
 
1430
                                ber_free( ber, 1 );
 
1431
                                Debug( LDAP_DEBUG_ANY, "%s: "
 
1432
                                        "chaining behavior control encoding error!\n",
 
1433
                                        c->log, 0, 0 );
 
1434
                                return 1;
 
1435
                        }
 
1436
 
 
1437
                        if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
 
1438
                                exit( EXIT_FAILURE );
 
1439
                        }
 
1440
 
 
1441
                } else {
 
1442
                        BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
 
1443
                }
 
1444
 
 
1445
                lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
 
1446
                lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
 
1447
 
 
1448
                if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
 
1449
                {
 
1450
                        Debug( LDAP_DEBUG_ANY, "%s: "
 
1451
                                "unable to parse chaining control%s%s.\n",
 
1452
                                c->log, rs.sr_text ? ": " : "",
 
1453
                                rs.sr_text ? rs.sr_text : "" );
 
1454
                        return 1;
 
1455
                }
 
1456
 
 
1457
                lc->lc_chaining_ctrlflag = op.o_chaining;
 
1458
 
 
1459
                lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
 
1460
 
 
1461
                rc = 0;
 
1462
#else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1463
                Debug( LDAP_DEBUG_ANY, "%s: "
 
1464
                        "\"chaining\" control unsupported (ignored).\n",
 
1465
                        c->log, 0, 0 );
 
1466
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1467
                } break;
 
1468
 
 
1469
        case CH_CACHE_URI:
 
1470
                if ( c->value_int ) {
 
1471
                        lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
 
1472
                } else {
 
1473
                        lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
 
1474
                }
 
1475
                break;
 
1476
 
 
1477
        case CH_MAX_DEPTH:
 
1478
                if ( c->value_int < 0 ) {
 
1479
                        snprintf( c->cr_msg, sizeof( c->cr_msg ),
 
1480
                                "<%s> invalid max referral depth %d",
 
1481
                                c->argv[0], c->value_int );
 
1482
                        Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
 
1483
                                c->log, c->cr_msg, 0 );
 
1484
                        rc = 1;
 
1485
                        break;
 
1486
                }
 
1487
                lc->lc_max_depth = c->value_int;
 
1488
 
 
1489
        case CH_RETURN_ERR:
 
1490
                if ( c->value_int ) {
 
1491
                        lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
 
1492
                } else {
 
1493
                        lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
 
1494
                }
 
1495
                break;
 
1496
 
 
1497
        default:
 
1498
                assert( 0 );
 
1499
                return 1;
 
1500
        }
 
1501
        return rc;
 
1502
}
 
1503
 
 
1504
static int
 
1505
ldap_chain_db_init(
 
1506
        BackendDB *be,
 
1507
        ConfigReply *cr )
 
1508
{
 
1509
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
1510
        ldap_chain_t    *lc = NULL;
 
1511
 
 
1512
        if ( lback == NULL ) {
 
1513
                static BackendInfo      lback2;
 
1514
 
 
1515
                lback = backend_info( "ldap" );
 
1516
 
 
1517
                if ( lback == NULL ) {
 
1518
                        return 1;
 
1519
                }
 
1520
 
 
1521
                lback2 = *lback;
 
1522
                lback2.bi_type = ldapchain.on_bi.bi_type;
 
1523
                lback = &lback2;
 
1524
        }
 
1525
 
 
1526
        lc = ch_malloc( sizeof( ldap_chain_t ) );
 
1527
        if ( lc == NULL ) {
 
1528
                return 1;
 
1529
        }
 
1530
        memset( lc, 0, sizeof( ldap_chain_t ) );
 
1531
        lc->lc_max_depth = 1;
 
1532
        ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
 
1533
 
 
1534
        on->on_bi.bi_private = (void *)lc;
 
1535
 
 
1536
        return 0;
 
1537
}
 
1538
 
 
1539
static int
 
1540
ldap_chain_db_config(
 
1541
        BackendDB       *be,
 
1542
        const char      *fname,
 
1543
        int             lineno,
 
1544
        int             argc,
 
1545
        char            **argv )
 
1546
{
 
1547
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
1548
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1549
 
 
1550
        int             rc = SLAP_CONF_UNKNOWN;
 
1551
                
 
1552
        if ( lc->lc_common_li == NULL ) {
 
1553
                void    *be_private = be->be_private;
 
1554
                ldap_chain_db_init_common( be );
 
1555
                lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
 
1556
                be->be_private = be_private;
 
1557
        }
 
1558
 
 
1559
        /* Something for the chain database? */
 
1560
        if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
 
1561
                char            *save_argv0 = argv[ 0 ];
 
1562
                BackendInfo     *bd_info = be->bd_info;
 
1563
                void            *be_private = be->be_private;
 
1564
                ConfigOCs       *be_cf_ocs = be->be_cf_ocs;
 
1565
                static char     *allowed_argv[] = {
 
1566
                        /* special: put URI here, so in the meanwhile
 
1567
                         * it detects whether a new URI is being provided */
 
1568
                        "uri",
 
1569
                        "nretries",
 
1570
                        "timeout",
 
1571
                        /* flags */
 
1572
                        "tls",
 
1573
                        /* FIXME: maybe rebind-as-user should be allowed
 
1574
                         * only within known URIs... */
 
1575
                        "rebind-as-user",
 
1576
                        "chase-referrals",
 
1577
                        "t-f-support",
 
1578
                        "proxy-whoami",
 
1579
                        NULL
 
1580
                };
 
1581
                int             which_argv = -1;
 
1582
 
 
1583
                argv[ 0 ] += STRLENOF( "chain-" );
 
1584
 
 
1585
                for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
 
1586
                        if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
 
1587
                                break;
 
1588
                        }
 
1589
                }
 
1590
 
 
1591
                if ( allowed_argv[ which_argv ] == NULL ) {
 
1592
                        which_argv = -1;
 
1593
 
 
1594
                        if ( lc->lc_cfg_li == lc->lc_common_li ) {
 
1595
                                Debug( LDAP_DEBUG_ANY, "%s: line %d: "
 
1596
                                        "\"%s\" only allowed within a URI directive.\n.",
 
1597
                                        fname, lineno, argv[ 0 ] );
 
1598
                                return 1;
 
1599
                        }
 
1600
                }
 
1601
 
 
1602
                if ( which_argv == 0 ) {
 
1603
                        rc = ldap_chain_db_init_one( be );
 
1604
                        if ( rc != 0 ) {
 
1605
                                Debug( LDAP_DEBUG_ANY, "%s: line %d: "
 
1606
                                        "underlying slapd-ldap initialization failed.\n.",
 
1607
                                        fname, lineno, 0 );
 
1608
                                return 1;
 
1609
                        }
 
1610
                        lc->lc_cfg_li = be->be_private;
 
1611
                }
 
1612
 
 
1613
                /* TODO: add checks on what other slapd-ldap(5) args
 
1614
                 * should be put in the template; this is not quite
 
1615
                 * harmful, because attributes that shouldn't don't
 
1616
                 * get actually used, but the user should at least
 
1617
                 * be warned.
 
1618
                 */
 
1619
 
 
1620
                be->bd_info = lback;
 
1621
                be->be_private = (void *)lc->lc_cfg_li;
 
1622
                be->be_cf_ocs = lback->bi_cf_ocs;
 
1623
 
 
1624
                rc = config_generic_wrapper( be, fname, lineno, argc, argv );
 
1625
 
 
1626
                argv[ 0 ] = save_argv0;
 
1627
                be->be_cf_ocs = be_cf_ocs;
 
1628
                be->be_private = be_private;
 
1629
                be->bd_info = bd_info;
 
1630
 
 
1631
                if ( which_argv == 0 ) {
 
1632
private_destroy:;
 
1633
                        if ( rc != 0 ) {
 
1634
                                BackendDB               db = *be;
 
1635
 
 
1636
                                db.bd_info = lback;
 
1637
                                db.be_private = (void *)lc->lc_cfg_li;
 
1638
                                ldap_chain_db_destroy_one( &db, NULL );
 
1639
                                lc->lc_cfg_li = NULL;
 
1640
 
 
1641
                        } else {
 
1642
                                if ( lc->lc_cfg_li->li_bvuri == NULL
 
1643
                                        || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
 
1644
                                        || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
 
1645
                                {
 
1646
                                        Debug( LDAP_DEBUG_ANY, "%s: line %d: "
 
1647
                                                "no URI list allowed in slapo-chain.\n",
 
1648
                                                fname, lineno, 0 );
 
1649
                                        rc = 1;
 
1650
                                        goto private_destroy;
 
1651
                                }
 
1652
 
 
1653
                                if ( avl_insert( &lc->lc_lai.lai_tree,
 
1654
                                        (caddr_t)lc->lc_cfg_li,
 
1655
                                        ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
 
1656
                                {
 
1657
                                        Debug( LDAP_DEBUG_ANY, "%s: line %d: "
 
1658
                                                "duplicate URI in slapo-chain.\n",
 
1659
                                                fname, lineno, 0 );
 
1660
                                        rc = 1;
 
1661
                                        goto private_destroy;
 
1662
                                }
 
1663
                        }
 
1664
                }
 
1665
        }
 
1666
        
 
1667
        return rc;
 
1668
}
 
1669
 
 
1670
enum db_which {
 
1671
        db_open = 0,
 
1672
        db_close,
 
1673
        db_destroy,
 
1674
 
 
1675
        db_last
 
1676
};
 
1677
 
 
1678
typedef struct ldap_chain_db_apply_t {
 
1679
        BackendDB       *be;
 
1680
        BI_db_func      *func;
 
1681
} ldap_chain_db_apply_t;
 
1682
 
 
1683
static int
 
1684
ldap_chain_db_apply( void *datum, void *arg )
 
1685
{
 
1686
        ldapinfo_t              *li = (ldapinfo_t *)datum;
 
1687
        ldap_chain_db_apply_t   *lca = (ldap_chain_db_apply_t *)arg;
 
1688
 
 
1689
        lca->be->be_private = (void *)li;
 
1690
 
 
1691
        return lca->func( lca->be, NULL );
 
1692
}
 
1693
 
 
1694
static int
 
1695
ldap_chain_db_func(
 
1696
        BackendDB *be,
 
1697
        enum db_which which
 
1698
)
 
1699
{
 
1700
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
1701
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1702
 
 
1703
        int             rc = 0;
 
1704
 
 
1705
        if ( lc ) {
 
1706
                BI_db_func      *func = (&lback->bi_db_open)[ which ];
 
1707
 
 
1708
                if ( func != NULL && lc->lc_common_li != NULL ) {
 
1709
                        BackendDB               db = *be;
 
1710
 
 
1711
                        db.bd_info = lback;
 
1712
                        db.be_private = lc->lc_common_li;
 
1713
 
 
1714
                        rc = func( &db, NULL );
 
1715
 
 
1716
                        if ( rc != 0 ) {
 
1717
                                return rc;
 
1718
                        }
 
1719
 
 
1720
                        if ( lc->lc_lai.lai_tree != NULL ) {
 
1721
                                ldap_chain_db_apply_t   lca;
 
1722
 
 
1723
                                lca.be = &db;
 
1724
                                lca.func = func;
 
1725
 
 
1726
                                rc = avl_apply( lc->lc_lai.lai_tree,
 
1727
                                        ldap_chain_db_apply, (void *)&lca,
 
1728
                                        1, AVL_INORDER ) != AVL_NOMORE;
 
1729
                        }
 
1730
                }
 
1731
        }
 
1732
 
 
1733
        return rc;
 
1734
}
 
1735
 
 
1736
static int
 
1737
ldap_chain_db_open(
 
1738
        BackendDB       *be,
 
1739
        ConfigReply     *cr )
 
1740
{
 
1741
        slap_overinst   *on = (slap_overinst *) be->bd_info;
 
1742
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1743
        slap_mask_t     monitoring;
 
1744
        int             rc = 0;
 
1745
 
 
1746
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1747
        rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
 
1748
        if ( rc != 0 ) {
 
1749
                return rc;
 
1750
        }
 
1751
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
1752
 
 
1753
        if ( lc->lc_common_li == NULL ) {
 
1754
                void    *be_private = be->be_private;
 
1755
                ldap_chain_db_init_common( be );
 
1756
                lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
 
1757
                be->be_private = be_private;
 
1758
        }
 
1759
 
 
1760
        /* filter out and restore monitoring */
 
1761
        monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
 
1762
        SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
 
1763
        rc = ldap_chain_db_func( be, db_open );
 
1764
        SLAP_DBFLAGS( be ) |= monitoring;
 
1765
 
 
1766
        return rc;
 
1767
}
 
1768
 
 
1769
static int
 
1770
ldap_chain_db_close(
 
1771
        BackendDB       *be,
 
1772
        ConfigReply     *cr )
 
1773
{
 
1774
        return ldap_chain_db_func( be, db_close );
 
1775
}
 
1776
 
 
1777
static int
 
1778
ldap_chain_db_destroy(
 
1779
        BackendDB       *be,
 
1780
        ConfigReply     *cr )
 
1781
{
 
1782
        slap_overinst   *on = (slap_overinst *) be->bd_info;
 
1783
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1784
 
 
1785
        int             rc;
 
1786
 
 
1787
        rc = ldap_chain_db_func( be, db_destroy );
 
1788
 
 
1789
        if ( lc ) {
 
1790
                avl_free( lc->lc_lai.lai_tree, NULL );
 
1791
                ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
 
1792
                ch_free( lc );
 
1793
        }
 
1794
 
 
1795
        return rc;
 
1796
}
 
1797
 
 
1798
/*
 
1799
 * inits one instance of the slapd-ldap backend, and stores
 
1800
 * the private info in be_private of the arg
 
1801
 */
 
1802
static int
 
1803
ldap_chain_db_init_common(
 
1804
        BackendDB       *be )
 
1805
{
 
1806
        BackendInfo     *bi = be->bd_info;
 
1807
        ldapinfo_t      *li;
 
1808
        int             rc;
 
1809
 
 
1810
        be->bd_info = lback;
 
1811
        be->be_private = NULL;
 
1812
        rc = lback->bi_db_init( be, NULL );
 
1813
        if ( rc != 0 ) {
 
1814
                return rc;
 
1815
        }
 
1816
        li = (ldapinfo_t *)be->be_private;
 
1817
        li->li_urllist_f = NULL;
 
1818
        li->li_urllist_p = NULL;
 
1819
 
 
1820
        be->bd_info = bi;
 
1821
 
 
1822
        return 0;
 
1823
}
 
1824
 
 
1825
/*
 
1826
 * inits one instance of the slapd-ldap backend, stores
 
1827
 * the private info in be_private of the arg and fills
 
1828
 * selected fields with data from the template.
 
1829
 *
 
1830
 * NOTE: add checks about the other fields of the template,
 
1831
 * which are ignored and SHOULD NOT be configured by the user.
 
1832
 */
 
1833
static int
 
1834
ldap_chain_db_init_one(
 
1835
        BackendDB       *be )
 
1836
{
 
1837
        slap_overinst   *on = (slap_overinst *)be->bd_info;
 
1838
        ldap_chain_t    *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1839
 
 
1840
        BackendInfo     *bi = be->bd_info;
 
1841
        ldapinfo_t      *li;
 
1842
 
 
1843
        slap_op_t       t;
 
1844
 
 
1845
        be->bd_info = lback;
 
1846
        be->be_private = NULL;
 
1847
        t = lback->bi_db_init( be, NULL );
 
1848
        if ( t != 0 ) {
 
1849
                return t;
 
1850
        }
 
1851
        li = (ldapinfo_t *)be->be_private;
 
1852
        li->li_urllist_f = NULL;
 
1853
        li->li_urllist_p = NULL;
 
1854
 
 
1855
        /* copy common data */
 
1856
        li->li_nretries = lc->lc_common_li->li_nretries;
 
1857
        li->li_flags = lc->lc_common_li->li_flags;
 
1858
        li->li_version = lc->lc_common_li->li_version;
 
1859
        for ( t = 0; t < SLAP_OP_LAST; t++ ) {
 
1860
                li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
 
1861
        }
 
1862
        be->bd_info = bi;
 
1863
 
 
1864
        return 0;
 
1865
}
 
1866
 
 
1867
static int
 
1868
ldap_chain_db_open_one(
 
1869
        BackendDB       *be )
 
1870
{
 
1871
        if ( SLAP_DBMONITORING( be ) ) {
 
1872
                ldapinfo_t      *li = (ldapinfo_t *)be->be_private;
 
1873
 
 
1874
                if ( li->li_uri == NULL ) {
 
1875
                        ber_str2bv( "cn=Common Connections", 0, 1,
 
1876
                                &li->li_monitor_info.lmi_rdn );
 
1877
 
 
1878
                } else {
 
1879
                        char            *ptr;
 
1880
 
 
1881
                        li->li_monitor_info.lmi_rdn.bv_len
 
1882
                                = STRLENOF( "cn=" ) + strlen( li->li_uri );
 
1883
                        ptr = li->li_monitor_info.lmi_rdn.bv_val
 
1884
                                = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
 
1885
                        ptr = lutil_strcopy( ptr, "cn=" );
 
1886
                        ptr = lutil_strcopy( ptr, li->li_uri );
 
1887
                        ptr[ 0 ] = '\0';
 
1888
                }
 
1889
        }
 
1890
 
 
1891
        return lback->bi_db_open( be, NULL );
 
1892
}
 
1893
 
 
1894
typedef struct ldap_chain_conn_apply_t {
 
1895
        BackendDB       *be;
 
1896
        Connection      *conn;
 
1897
} ldap_chain_conn_apply_t;
 
1898
 
 
1899
static int
 
1900
ldap_chain_conn_apply( void *datum, void *arg )
 
1901
{
 
1902
        ldapinfo_t              *li = (ldapinfo_t *)datum;
 
1903
        ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
 
1904
 
 
1905
        lca->be->be_private = (void *)li;
 
1906
 
 
1907
        return lback->bi_connection_destroy( lca->be, lca->conn );
 
1908
}
 
1909
 
 
1910
static int
 
1911
ldap_chain_connection_destroy(
 
1912
        BackendDB *be,
 
1913
        Connection *conn
 
1914
)
 
1915
{
 
1916
        slap_overinst           *on = (slap_overinst *) be->bd_info;
 
1917
        ldap_chain_t            *lc = (ldap_chain_t *)on->on_bi.bi_private;
 
1918
        void                    *private = be->be_private;
 
1919
        ldap_chain_conn_apply_t lca;
 
1920
        int                     rc;
 
1921
 
 
1922
        be->be_private = NULL;
 
1923
        lca.be = be;
 
1924
        lca.conn = conn;
 
1925
        ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
 
1926
        rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
 
1927
                (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
 
1928
        ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
 
1929
        be->be_private = private;
 
1930
 
 
1931
        return rc;
 
1932
}
 
1933
 
 
1934
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
1935
static int
 
1936
ldap_chain_parse_ctrl(
 
1937
        Operation       *op,
 
1938
        SlapReply       *rs,
 
1939
        LDAPControl     *ctrl )
 
1940
{
 
1941
        ber_tag_t       tag;
 
1942
        BerElement      *ber;
 
1943
        ber_int_t       mode,
 
1944
                        behavior;
 
1945
 
 
1946
        if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
 
1947
                rs->sr_text = "Chaining behavior control specified multiple times";
 
1948
                return LDAP_PROTOCOL_ERROR;
 
1949
        }
 
1950
 
 
1951
        if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
 
1952
                rs->sr_text = "Chaining behavior control specified with pagedResults control";
 
1953
                return LDAP_PROTOCOL_ERROR;
 
1954
        }
 
1955
 
 
1956
        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
 
1957
                mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
 
1958
 
 
1959
        } else {
 
1960
                ber_len_t       len;
 
1961
 
 
1962
                /* Parse the control value
 
1963
                 *      ChainingBehavior ::= SEQUENCE { 
 
1964
                 *           resolveBehavior         Behavior OPTIONAL, 
 
1965
                 *           continuationBehavior    Behavior OPTIONAL } 
 
1966
                 *                             
 
1967
                 *      Behavior :: = ENUMERATED { 
 
1968
                 *           chainingPreferred       (0), 
 
1969
                 *           chainingRequired        (1), 
 
1970
                 *           referralsPreferred      (2), 
 
1971
                 *           referralsRequired       (3) } 
 
1972
                 */
 
1973
 
 
1974
                ber = ber_init( &ctrl->ldctl_value );
 
1975
                if( ber == NULL ) {
 
1976
                        rs->sr_text = "internal error";
 
1977
                        return LDAP_OTHER;
 
1978
                }
 
1979
 
 
1980
                tag = ber_scanf( ber, "{e" /* } */, &behavior );
 
1981
                /* FIXME: since the whole SEQUENCE is optional,
 
1982
                 * should we accept no enumerations at all? */
 
1983
                if ( tag != LBER_ENUMERATED ) {
 
1984
                        rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
 
1985
                        return LDAP_PROTOCOL_ERROR;
 
1986
                }
 
1987
 
 
1988
                switch ( behavior ) {
 
1989
                case LDAP_CHAINING_PREFERRED:
 
1990
                        mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
 
1991
                        break;
 
1992
 
 
1993
                case LDAP_CHAINING_REQUIRED:
 
1994
                        mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
 
1995
                        break;
 
1996
 
 
1997
                case LDAP_REFERRALS_PREFERRED:
 
1998
                        mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
 
1999
                        break;
 
2000
 
 
2001
                case LDAP_REFERRALS_REQUIRED:
 
2002
                        mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
 
2003
                        break;
 
2004
 
 
2005
                default:
 
2006
                        rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
 
2007
                        return LDAP_PROTOCOL_ERROR;
 
2008
                }
 
2009
 
 
2010
                tag = ber_peek_tag( ber, &len );
 
2011
                if ( tag == LBER_ENUMERATED ) {
 
2012
                        tag = ber_scanf( ber, "e", &behavior );
 
2013
                        if ( tag == LBER_ERROR ) {
 
2014
                                rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
 
2015
                                return LDAP_PROTOCOL_ERROR;
 
2016
                        }
 
2017
                }
 
2018
 
 
2019
                if ( tag == LBER_DEFAULT ) {
 
2020
                        mode |= SLAP_CH_CONTINUATION_DEFAULT;
 
2021
 
 
2022
                } else {
 
2023
                        switch ( behavior ) {
 
2024
                        case LDAP_CHAINING_PREFERRED:
 
2025
                                mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
 
2026
                                break;
 
2027
 
 
2028
                        case LDAP_CHAINING_REQUIRED:
 
2029
                                mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
 
2030
                                break;
 
2031
 
 
2032
                        case LDAP_REFERRALS_PREFERRED:
 
2033
                                mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
 
2034
                                break;
 
2035
 
 
2036
                        case LDAP_REFERRALS_REQUIRED:
 
2037
                                mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
 
2038
                                break;
 
2039
 
 
2040
                        default:
 
2041
                                rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
 
2042
                                return LDAP_PROTOCOL_ERROR;
 
2043
                        }
 
2044
                }
 
2045
 
 
2046
                if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
 
2047
                        rs->sr_text = "Chaining behavior control: decoding error";
 
2048
                        return LDAP_PROTOCOL_ERROR;
 
2049
                }
 
2050
 
 
2051
                (void) ber_free( ber, 1 );
 
2052
        }
 
2053
 
 
2054
        op->o_chaining = mode | ( ctrl->ldctl_iscritical
 
2055
                        ? SLAP_CONTROL_CRITICAL
 
2056
                        : SLAP_CONTROL_NONCRITICAL );
 
2057
 
 
2058
        return LDAP_SUCCESS;
 
2059
}
 
2060
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
2061
 
 
2062
int
 
2063
chain_initialize( void )
 
2064
{
 
2065
        int     rc;
 
2066
 
 
2067
        /* Make sure we don't exceed the bits reserved for userland */
 
2068
        config_check_userland( CH_LAST );
 
2069
 
 
2070
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
 
2071
        rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
 
2072
                        /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
 
2073
                        ldap_chain_parse_ctrl, &sc_chainingBehavior );
 
2074
        if ( rc != LDAP_SUCCESS ) {
 
2075
                Debug( LDAP_DEBUG_ANY, "slapd-chain: "
 
2076
                        "unable to register chaining behavior control: %d.\n",
 
2077
                        rc, 0, 0 );
 
2078
                return rc;
 
2079
        }
 
2080
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
 
2081
 
 
2082
        ldapchain.on_bi.bi_type = "chain";
 
2083
        ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
 
2084
        ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
 
2085
        ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
 
2086
        ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
 
2087
        ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
 
2088
 
 
2089
        ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
 
2090
 
 
2091
        ldapchain.on_response = ldap_chain_response;
 
2092
 
 
2093
        ldapchain.on_bi.bi_cf_ocs = chainocs;
 
2094
 
 
2095
        rc = config_register_schema( chaincfg, chainocs );
 
2096
        if ( rc ) {
 
2097
                return rc;
 
2098
        }
 
2099
 
 
2100
        return overlay_register( &ldapchain );
 
2101
}
 
2102