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/>.
5
* Copyright 2003-2008 The OpenLDAP Foundation.
6
* Portions Copyright 2003 Howard Chu.
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted only as authorized by the OpenLDAP
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>.
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.
27
#include <ac/string.h>
28
#include <ac/socket.h>
32
#include "back-ldap.h"
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)
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)
58
static int sc_chainingBehavior;
59
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
65
} ldap_chain_status_t;
66
static BackendInfo *lback;
68
typedef struct ldap_chain_t {
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
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.
82
/* "common" configuration info (anything occurring before an "uri") */
83
ldapinfo_t *lc_common_li;
85
/* current configuration info */
86
ldapinfo_t *lc_cfg_li;
88
/* tree of configured[/generated?] "uri" info */
89
ldap_avl_info_t lc_lai;
91
/* max depth in nested referrals chaining */
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)
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 )
105
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
106
LDAPControl lc_chaining_ctrl;
107
char lc_chaining_ctrlflag;
108
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
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) )
117
typedef struct ldap_chain_cb_t {
118
ldap_chain_status_t lb_status;
139
static slap_overinst ldapchain;
141
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
143
chaining_control_add(
146
LDAPControl ***oldctrlsp )
148
LDAPControl **ctrls = NULL;
151
*oldctrlsp = op->o_ctrls;
153
/* default chaining control not defined */
154
if ( !LDAP_CHAIN_CHAINING( lc ) ) {
158
/* already present */
159
if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
163
/* FIXME: check other incompatibilities */
165
/* add to other controls */
167
for ( c = 0; op->o_ctrls[ c ]; c++ )
171
ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
172
ctrls[ 0 ] = &lc->lc_chaining_ctrl;
174
for ( c = 0; op->o_ctrls[ c ]; c++ ) {
175
ctrls[ c + 1 ] = op->o_ctrls[ c ];
178
ctrls[ c + 1 ] = NULL;
182
op->o_chaining = lc->lc_chaining_ctrlflag;
188
chaining_control_remove(
190
LDAPControl ***oldctrlsp )
192
LDAPControl **oldctrls = *oldctrlsp;
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
197
if ( op->o_ctrls != oldctrls ) {
198
assert( op->o_ctrls != NULL );
199
assert( op->o_ctrls[ 0 ] != NULL );
204
op->o_ctrls = oldctrls;
211
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
214
ldap_chain_uri_cmp( const void *c1, const void *c2 )
216
const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
217
const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
219
assert( li1->li_bvuri != NULL );
220
assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
221
assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
223
assert( li2->li_bvuri != NULL );
224
assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
225
assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
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 ] );
232
ldap_chain_uri_dup( void *c1, void *c2 )
234
ldapinfo_t *li1 = (ldapinfo_t *)c1;
235
ldapinfo_t *li2 = (ldapinfo_t *)c2;
237
assert( li1->li_bvuri != NULL );
238
assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
239
assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
241
assert( li2->li_bvuri != NULL );
242
assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
243
assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
245
/* Cannot have more than one shared session with same DN */
246
if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
254
* Search specific response that strips entryDN from entries
257
ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
259
ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
261
assert( op->o_tag == LDAP_REQ_SEARCH );
263
/* if in error, don't proceed any further */
264
if ( lb->lb_status == LDAP_CH_ERR ) {
268
if ( rs->sr_type == REP_SEARCH ) {
269
Attribute **ap = &rs->sr_entry->e_attrs;
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 )
282
/* there SHOULD be one only! */
287
/* tell the frontend not to add generated
288
* operational attributes */
289
rs->sr_flags |= REP_NO_OPERATIONALS;
291
return SLAP_CB_CONTINUE;
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 );
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;
311
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
312
return SLAP_CB_CONTINUE;
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 )
319
rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
322
/* back-ldap tried to send result */
323
lb->lb_status = LDAP_CH_RES;
330
* Dummy response that simply traces if back-ldap tried to send
331
* anything to the client
334
ldap_chain_cb_response( Operation *op, SlapReply *rs )
336
ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
338
/* if in error, don't proceed any further */
339
if ( lb->lb_status == LDAP_CH_ERR ) {
343
if ( rs->sr_type == REP_RESULT ) {
345
switch ( rs->sr_err ) {
346
case LDAP_COMPARE_TRUE:
347
case LDAP_COMPARE_FALSE:
348
if ( op->o_tag != LDAP_REQ_COMPARE ) {
354
lb->lb_status = LDAP_CH_RES;
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 );
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;
374
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
381
} else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
383
/* strip the entryDN attribute, but keep returning results */
384
(void)ldap_chain_cb_search_response( op, rs );
387
return SLAP_CB_CONTINUE;
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 } };
404
/* NOTE: returned if ref is empty... */
408
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
409
LDAPControl **ctrls = NULL;
411
(void)chaining_control_add( lc, op, &ctrls );
412
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
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,
426
/* We're setting the URI of the first referral;
427
* what if there are more?
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.
438
* so we actually need to follow exactly one,
439
* and we can assume any is fine.
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 ) {
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 */
468
li.li_uri = ldap_url_desc2str( srv );
469
srv->lud_dn = dn.bv_val;
470
ldap_free_urldesc( srv );
472
if ( rc != LDAP_SUCCESS ) {
478
if ( li.li_uri == NULL ) {
481
goto further_cleanup;
487
ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
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 );
496
op->o_bd->be_private = (void *)lip;
499
rc = ldap_chain_db_init_one( op->o_bd );
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 );
509
lip->li_bvuri = NULL;
510
(void)ldap_chain_db_destroy_one( op->o_bd, NULL);
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 ) )
519
/* someone just inserted another;
520
* don't bother, use this and then
524
ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
532
lb->lb_depth = depth + 1;
534
rc = op_f( op, &rs2 );
536
/* note the first error */
537
if ( first_rc == -1 ) {
542
ldap_memfree( li.li_uri );
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 );
553
if ( !BER_BVISNULL( &pdn ) ) {
554
op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
556
op->o_req_dn = save_req_dn;
558
if ( !BER_BVISNULL( &ndn ) ) {
559
op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
561
op->o_req_ndn = save_req_ndn;
563
if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
571
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
572
(void)chaining_control_remove( op, &ctrls );
573
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
575
if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
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 } };
596
struct berval odn = op->o_req_dn,
597
ondn = op->o_req_ndn;
598
slap_response *save_response = op->o_callback->sc_response;
603
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
604
LDAPControl **ctrls = NULL;
606
(void)chaining_control_add( lc, op, &ctrls );
607
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
609
rs->sr_type = REP_SEARCH;
611
op->o_callback->sc_response = ldap_chain_cb_search_response;
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?) */
619
for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
620
SlapReply rs2 = { 0 };
622
struct berval save_req_dn = op->o_req_dn,
623
save_req_ndn = op->o_req_ndn,
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 ) {
634
rs->sr_err = LDAP_OTHER;
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 */
648
srv->lud_scope = LDAP_SCOPE_DEFAULT;
649
li.li_uri = ldap_url_desc2str( srv );
650
srv->lud_dn = dn.bv_val;
653
ldap_free_urldesc( srv );
655
if ( rc != LDAP_SUCCESS ) {
661
if ( li.li_uri == NULL ) {
664
goto further_cleanup;
670
ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
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 );
679
op->o_bd->be_private = (void *)lip;
682
/* if none is found, create a temporary... */
683
rc = ldap_chain_db_init_one( op->o_bd );
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 );
693
lip->li_bvuri = NULL;
694
(void)ldap_chain_db_destroy_one( op->o_bd, NULL );
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 ) )
703
/* someone just inserted another;
704
* don't bother, use this and then
708
ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
715
lb->lb_op_f = lback->bi_op_search;
716
lb->lb_depth = depth + 1;
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 ) {
726
ldap_memfree( li.li_uri );
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 );
737
if ( !BER_BVISNULL( &pdn ) ) {
738
op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
740
op->o_req_dn = save_req_dn;
742
if ( !BER_BVISNULL( &ndn ) ) {
743
op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
745
op->o_req_ndn = save_req_ndn;
747
if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
755
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
756
(void)chaining_control_remove( op, &ctrls );
757
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
760
op->o_req_ndn = ondn;
761
op->o_callback->sc_response = save_response;
762
rs->sr_type = REP_SEARCHREF;
765
if ( rc != LDAP_SUCCESS ) {
766
/* couldn't chase any of the referrals */
767
if ( first_rc != -1 ) {
771
rc = SLAP_CB_CONTINUE;
779
ldap_chain_response( Operation *op, SlapReply *rs )
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,
788
const char *text = NULL;
791
struct berval ndn = op->o_ndn;
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 */
800
if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
801
return SLAP_CB_CONTINUE;
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;
812
chain_mask = SLAP_CH_RESOLVE_MASK;
813
chain_shift = SLAP_CH_RESOLVE_SHIFT;
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;
824
chain_mask = SLAP_CH_CONTINUATION_MASK;
825
chain_shift = SLAP_CH_CONTINUATION_SHIFT;
829
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
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://)
841
SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
846
matched = rs->sr_matched;
847
rs->sr_matched = NULL;
851
/* we need this to know if back-ldap returned any result */
853
sc2.sc_private = &lb;
854
sc2.sc_response = ldap_chain_cb_response;
855
op->o_callback = &sc2;
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).
862
* FIXME: the idassert-authcDN is one, will it be fine regardless
863
* of the URI we obtain from the referral?
866
switch ( op->o_tag ) {
867
case LDAP_REQ_BIND: {
868
struct berval rndn = op->o_req_ndn;
869
Connection *conn = op->o_conn;
871
/* FIXME: can we really get a referral for binds? */
872
op->o_req_ndn = slap_empty_bv;
874
rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
875
op->o_req_ndn = rndn;
881
rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
884
case LDAP_REQ_DELETE:
885
rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
888
case LDAP_REQ_MODRDN:
889
rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
892
case LDAP_REQ_MODIFY:
893
rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
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 ) {
903
case LDAP_REQ_SEARCH:
904
if ( rs->sr_type == REP_SEARCHREF ) {
905
rc = ldap_chain_search( op, rs, ref, 0 );
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
912
if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
913
rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
916
rc = SLAP_CB_CONTINUE;
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
926
/* FIXME: what about chaining? */
927
if ( rc != SLAPD_ABANDON ) {
929
send_ldap_extended( op, rs );
932
lb.lb_status = LDAP_CH_RES;
936
rc = SLAP_CB_CONTINUE;
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 );
957
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
958
if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
962
switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
963
case LDAP_CHAINING_REQUIRED:
965
op->o_callback = NULL;
966
send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
967
"operation cannot be completed without chaining" );
971
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
972
if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
974
rs->sr_type = sr_type;
977
rc = SLAP_CB_CONTINUE;
979
rs->sr_type = sr_type;
981
rs->sr_matched = matched;
984
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
987
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
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 );
998
rs->sr_type = sr_type;
1000
rs->sr_matched = matched;
1003
op->o_callback = sc;
1009
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1011
ldap_chain_parse_ctrl(
1014
LDAPControl *ctrl );
1017
str2chain( const char *s )
1019
if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1020
return LDAP_CHAINING_PREFERRED;
1022
} else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1023
return LDAP_CHAINING_REQUIRED;
1025
} else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1026
return LDAP_REFERRALS_PREFERRED;
1028
} else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1029
return LDAP_REFERRALS_REQUIRED;
1034
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1049
static ConfigDriver chain_cf_gen;
1050
static ConfigCfAdd chain_cfadd;
1051
static ConfigLDAPadd chain_ldadd;
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 }
1081
static ConfigOCs chainocs[] = {
1082
{ "( OLcfgOvOc:3.1 "
1083
"NAME 'olcChainConfig' "
1084
"DESC 'Chain configuration' "
1085
"SUP olcOverlayConfig "
1087
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1088
"olcChainingBehavior $ "
1089
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1090
"olcChainCacheURI $ "
1091
"olcChainMaxReferralDepth $ "
1092
"olcChainReturnError "
1094
Cft_Overlay, chaincfg, NULL, chain_cfadd },
1095
{ "( OLcfgOvOc:3.2 "
1096
"NAME 'olcChainDatabase' "
1097
"DESC 'Chain remote server configuration' "
1099
Cft_Misc, chaincfg, chain_ldadd },
1104
chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1111
AttributeDescription *ad = NULL;
1117
if ( p->ce_type != Cft_Overlay
1119
|| p->ce_bi->bi_cf_ocs != chainocs )
1121
return LDAP_CONSTRAINT_VIOLATION;
1124
on = (slap_overinst *)p->ce_bi;
1125
lc = (ldap_chain_t *)on->on_bi.bi_private;
1127
assert( ca->be == NULL );
1128
ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1130
ca->be->bd_info = (BackendInfo *)on;
1132
rc = slap_str2ad( "olcDbURI", &ad, &text );
1133
assert( rc == LDAP_SUCCESS );
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;
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;
1157
if ( lc->lc_common_li == NULL ) {
1158
rc = ldap_chain_db_init_common( ca->be );
1161
rc = ldap_chain_db_init_one( ca->be );
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;
1171
li = ca->be->be_private;
1173
if ( lc->lc_common_li == NULL ) {
1174
lc->lc_common_li = li;
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 ) )
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;
1191
if ( rc != LDAP_SUCCESS ) {
1192
(void)ldap_chain_db_destroy_one( ca->be, NULL );
1200
typedef struct ldap_chain_cfadd_apply_t {
1206
} ldap_chain_cfadd_apply_t;
1209
ldap_chain_cfadd_apply( void *datum, void *arg )
1211
ldapinfo_t *li = (ldapinfo_t *)datum;
1212
ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
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;
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] );
1231
chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
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;
1238
if ( lback->bi_cf_ocs ) {
1239
ldap_chain_cfadd_apply_t lca = { 0 };
1247
(void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1249
(void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1250
&lca, 1, AVL_INORDER );
1252
ca->be->be_private = priv;
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 },
1266
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1269
chain_cf_gen( ConfigArgs *c )
1271
slap_overinst *on = (slap_overinst *)c->bi;
1272
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1276
if ( c->op == SLAP_CONFIG_EMIT ) {
1278
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1280
struct berval resolve = BER_BVNULL,
1281
continuation = BER_BVNULL;
1283
if ( !LDAP_CHAIN_CHAINING( lc ) ) {
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 );
1290
c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
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 );
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" );
1308
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1311
c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1315
c->value_int = lc->lc_max_depth;
1319
c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1328
} else if ( c->op == LDAP_MOD_DELETE ) {
1334
lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1342
lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1353
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1354
char **argv = c->argv;
1356
BerElementBuffer berbuf;
1357
BerElement *ber = (BerElement *)&berbuf;
1361
Operation op = { 0 };
1362
SlapReply rs = { 0 };
1364
lc->lc_chaining_ctrlflag = 0;
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 );
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 );
1387
} else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1391
Debug( LDAP_DEBUG_ANY, "%s: "
1392
"unknown option in \"chain-chaining\".\n",
1398
if ( resolve != -1 || continuation != -1 ) {
1401
if ( resolve == -1 ) {
1403
resolve = SLAP_CHAINING_DEFAULT;
1406
ber_init2( ber, NULL, LBER_USE_DER );
1408
err = ber_printf( ber, "{e" /* } */, resolve );
1411
Debug( LDAP_DEBUG_ANY, "%s: "
1412
"chaining behavior control encoding error!\n",
1417
if ( continuation > -1 ) {
1418
err = ber_printf( ber, "e", continuation );
1421
Debug( LDAP_DEBUG_ANY, "%s: "
1422
"chaining behavior control encoding error!\n",
1428
err = ber_printf( ber, /* { */ "N}" );
1431
Debug( LDAP_DEBUG_ANY, "%s: "
1432
"chaining behavior control encoding error!\n",
1437
if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1438
exit( EXIT_FAILURE );
1442
BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1445
lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1446
lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1448
if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
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 : "" );
1457
lc->lc_chaining_ctrlflag = op.o_chaining;
1459
lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1462
#else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1463
Debug( LDAP_DEBUG_ANY, "%s: "
1464
"\"chaining\" control unsupported (ignored).\n",
1466
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1470
if ( c->value_int ) {
1471
lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1473
lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
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 );
1487
lc->lc_max_depth = c->value_int;
1490
if ( c->value_int ) {
1491
lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1493
lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1509
slap_overinst *on = (slap_overinst *)be->bd_info;
1510
ldap_chain_t *lc = NULL;
1512
if ( lback == NULL ) {
1513
static BackendInfo lback2;
1515
lback = backend_info( "ldap" );
1517
if ( lback == NULL ) {
1522
lback2.bi_type = ldapchain.on_bi.bi_type;
1526
lc = ch_malloc( sizeof( ldap_chain_t ) );
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 );
1534
on->on_bi.bi_private = (void *)lc;
1540
ldap_chain_db_config(
1547
slap_overinst *on = (slap_overinst *)be->bd_info;
1548
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1550
int rc = SLAP_CONF_UNKNOWN;
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;
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 */
1573
/* FIXME: maybe rebind-as-user should be allowed
1574
* only within known URIs... */
1581
int which_argv = -1;
1583
argv[ 0 ] += STRLENOF( "chain-" );
1585
for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1586
if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1591
if ( allowed_argv[ which_argv ] == NULL ) {
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 ] );
1602
if ( which_argv == 0 ) {
1603
rc = ldap_chain_db_init_one( be );
1605
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1606
"underlying slapd-ldap initialization failed.\n.",
1610
lc->lc_cfg_li = be->be_private;
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
1620
be->bd_info = lback;
1621
be->be_private = (void *)lc->lc_cfg_li;
1622
be->be_cf_ocs = lback->bi_cf_ocs;
1624
rc = config_generic_wrapper( be, fname, lineno, argc, argv );
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;
1631
if ( which_argv == 0 ) {
1637
db.be_private = (void *)lc->lc_cfg_li;
1638
ldap_chain_db_destroy_one( &db, NULL );
1639
lc->lc_cfg_li = NULL;
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 ] ) )
1646
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1647
"no URI list allowed in slapo-chain.\n",
1650
goto private_destroy;
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 ) )
1657
Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1658
"duplicate URI in slapo-chain.\n",
1661
goto private_destroy;
1678
typedef struct ldap_chain_db_apply_t {
1681
} ldap_chain_db_apply_t;
1684
ldap_chain_db_apply( void *datum, void *arg )
1686
ldapinfo_t *li = (ldapinfo_t *)datum;
1687
ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1689
lca->be->be_private = (void *)li;
1691
return lca->func( lca->be, NULL );
1700
slap_overinst *on = (slap_overinst *)be->bd_info;
1701
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1706
BI_db_func *func = (&lback->bi_db_open)[ which ];
1708
if ( func != NULL && lc->lc_common_li != NULL ) {
1712
db.be_private = lc->lc_common_li;
1714
rc = func( &db, NULL );
1720
if ( lc->lc_lai.lai_tree != NULL ) {
1721
ldap_chain_db_apply_t lca;
1726
rc = avl_apply( lc->lc_lai.lai_tree,
1727
ldap_chain_db_apply, (void *)&lca,
1728
1, AVL_INORDER ) != AVL_NOMORE;
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;
1746
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1747
rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1751
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
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;
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;
1770
ldap_chain_db_close(
1774
return ldap_chain_db_func( be, db_close );
1778
ldap_chain_db_destroy(
1782
slap_overinst *on = (slap_overinst *) be->bd_info;
1783
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1787
rc = ldap_chain_db_func( be, db_destroy );
1790
avl_free( lc->lc_lai.lai_tree, NULL );
1791
ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1799
* inits one instance of the slapd-ldap backend, and stores
1800
* the private info in be_private of the arg
1803
ldap_chain_db_init_common(
1806
BackendInfo *bi = be->bd_info;
1810
be->bd_info = lback;
1811
be->be_private = NULL;
1812
rc = lback->bi_db_init( be, NULL );
1816
li = (ldapinfo_t *)be->be_private;
1817
li->li_urllist_f = NULL;
1818
li->li_urllist_p = NULL;
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.
1830
* NOTE: add checks about the other fields of the template,
1831
* which are ignored and SHOULD NOT be configured by the user.
1834
ldap_chain_db_init_one(
1837
slap_overinst *on = (slap_overinst *)be->bd_info;
1838
ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1840
BackendInfo *bi = be->bd_info;
1845
be->bd_info = lback;
1846
be->be_private = NULL;
1847
t = lback->bi_db_init( be, NULL );
1851
li = (ldapinfo_t *)be->be_private;
1852
li->li_urllist_f = NULL;
1853
li->li_urllist_p = NULL;
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 ];
1868
ldap_chain_db_open_one(
1871
if ( SLAP_DBMONITORING( be ) ) {
1872
ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1874
if ( li->li_uri == NULL ) {
1875
ber_str2bv( "cn=Common Connections", 0, 1,
1876
&li->li_monitor_info.lmi_rdn );
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 );
1891
return lback->bi_db_open( be, NULL );
1894
typedef struct ldap_chain_conn_apply_t {
1897
} ldap_chain_conn_apply_t;
1900
ldap_chain_conn_apply( void *datum, void *arg )
1902
ldapinfo_t *li = (ldapinfo_t *)datum;
1903
ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1905
lca->be->be_private = (void *)li;
1907
return lback->bi_connection_destroy( lca->be, lca->conn );
1911
ldap_chain_connection_destroy(
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;
1922
be->be_private = NULL;
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;
1934
#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1936
ldap_chain_parse_ctrl(
1946
if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1947
rs->sr_text = "Chaining behavior control specified multiple times";
1948
return LDAP_PROTOCOL_ERROR;
1951
if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1952
rs->sr_text = "Chaining behavior control specified with pagedResults control";
1953
return LDAP_PROTOCOL_ERROR;
1956
if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1957
mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1962
/* Parse the control value
1963
* ChainingBehavior ::= SEQUENCE {
1964
* resolveBehavior Behavior OPTIONAL,
1965
* continuationBehavior Behavior OPTIONAL }
1967
* Behavior :: = ENUMERATED {
1968
* chainingPreferred (0),
1969
* chainingRequired (1),
1970
* referralsPreferred (2),
1971
* referralsRequired (3) }
1974
ber = ber_init( &ctrl->ldctl_value );
1976
rs->sr_text = "internal error";
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;
1988
switch ( behavior ) {
1989
case LDAP_CHAINING_PREFERRED:
1990
mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1993
case LDAP_CHAINING_REQUIRED:
1994
mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1997
case LDAP_REFERRALS_PREFERRED:
1998
mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
2001
case LDAP_REFERRALS_REQUIRED:
2002
mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2006
rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2007
return LDAP_PROTOCOL_ERROR;
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;
2019
if ( tag == LBER_DEFAULT ) {
2020
mode |= SLAP_CH_CONTINUATION_DEFAULT;
2023
switch ( behavior ) {
2024
case LDAP_CHAINING_PREFERRED:
2025
mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2028
case LDAP_CHAINING_REQUIRED:
2029
mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2032
case LDAP_REFERRALS_PREFERRED:
2033
mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2036
case LDAP_REFERRALS_REQUIRED:
2037
mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2041
rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2042
return LDAP_PROTOCOL_ERROR;
2046
if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2047
rs->sr_text = "Chaining behavior control: decoding error";
2048
return LDAP_PROTOCOL_ERROR;
2051
(void) ber_free( ber, 1 );
2054
op->o_chaining = mode | ( ctrl->ldctl_iscritical
2055
? SLAP_CONTROL_CRITICAL
2056
: SLAP_CONTROL_NONCRITICAL );
2058
return LDAP_SUCCESS;
2060
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2063
chain_initialize( void )
2067
/* Make sure we don't exceed the bits reserved for userland */
2068
config_check_userland( CH_LAST );
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",
2080
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
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;
2089
ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2091
ldapchain.on_response = ldap_chain_response;
2093
ldapchain.on_bi.bi_cf_ocs = chainocs;
2095
rc = config_register_schema( chaincfg, chainocs );
2100
return overlay_register( &ldapchain );