1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2006 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>
31 #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 */
61 #define LDAP_CH_NONE ((void *)(0))
62 #define LDAP_CH_RES ((void *)(1))
63 #define LDAP_CH_ERR ((void *)(2))
65 static BackendInfo *lback;
67 typedef struct ldap_chain_t {
69 * A "template" ldapinfo_t gets all common configuration items;
70 * then, for each configured URI, an entry is created in the tree;
71 * all the specific configuration items get in the current URI
74 * Then, for each referral, extract the URI and lookup the
75 * related structure. If configured to do so, allow URIs
76 * not found in the structure to create a temporary one
77 * that chains anonymously; maybe it can also be added to
78 * the tree? Should be all configurable.
81 /* "common" configuration info (anything occurring before an "uri") */
82 ldapinfo_t *lc_common_li;
84 /* current configuration info */
85 ldapinfo_t *lc_cfg_li;
87 /* tree of configured[/generated?] "uri" info */
88 ldap_avl_info_t lc_lai;
91 #define LDAP_CHAIN_F_NONE (0x00U)
92 #define LDAP_CHAIN_F_CHAINING (0x01U)
93 #define LDAP_CHAIN_F_CACHE_URI (0x10U)
95 #define LDAP_CHAIN_CHAINING( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CHAINING ) == LDAP_CHAIN_F_CHAINING )
96 #define LDAP_CHAIN_CACHE_URI( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CACHE_URI ) == LDAP_CHAIN_F_CACHE_URI )
98 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
99 LDAPControl lc_chaining_ctrl;
100 char lc_chaining_ctrlflag;
101 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
104 static int ldap_chain_db_init_common( BackendDB *be );
105 static int ldap_chain_db_init_one( BackendDB *be );
106 #define ldap_chain_db_open_one(be) (lback)->bi_db_open( (be) )
107 #define ldap_chain_db_close_one(be) (0)
108 #define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
110 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
112 chaining_control_add(
115 LDAPControl ***oldctrlsp )
117 LDAPControl **ctrls = NULL;
120 *oldctrlsp = op->o_ctrls;
122 /* default chaining control not defined */
123 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
127 /* already present */
128 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
132 /* FIXME: check other incompatibilities */
134 /* add to other controls */
136 for ( c = 0; op->o_ctrls[ c ]; c++ )
140 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
141 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
143 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
144 ctrls[ c + 1 ] = op->o_ctrls[ c ];
147 ctrls[ c + 1 ] = NULL;
151 op->o_chaining = lc->lc_chaining_ctrlflag;
157 chaining_control_remove(
159 LDAPControl ***oldctrlsp )
161 LDAPControl **oldctrls = *oldctrlsp;
163 /* we assume that the first control is the chaining control
164 * added by the chain overlay, so it's the only one we explicitly
166 if ( op->o_ctrls != oldctrls ) {
167 assert( op->o_ctrls != NULL );
168 assert( op->o_ctrls[ 0 ] != NULL );
173 op->o_ctrls = oldctrls;
180 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
183 ldap_chain_uri_cmp( const void *c1, const void *c2 )
185 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
186 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
188 assert( li1->li_bvuri != NULL );
189 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
190 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
192 assert( li2->li_bvuri != NULL );
193 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
194 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
196 /* If local DNs don't match, it is definitely not a match */
197 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
201 ldap_chain_uri_dup( void *c1, void *c2 )
203 ldapinfo_t *li1 = (ldapinfo_t *)c1;
204 ldapinfo_t *li2 = (ldapinfo_t *)c2;
206 assert( li1->li_bvuri != NULL );
207 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
208 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
210 assert( li2->li_bvuri != NULL );
211 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
212 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
214 /* Cannot have more than one shared session with same DN */
215 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
223 ldap_chain_operational( Operation *op, SlapReply *rs )
225 /* Trap entries generated by back-ldap.
227 * FIXME: we need a better way to recognize them; a cleaner
228 * solution would be to be able to intercept the response
229 * of be_operational(), so that we can divert only those
230 * calls that fail because operational attributes were
231 * requested for entries that do not belong to the underlying
232 * database. This fix is likely to intercept also entries
233 * generated by back-perl and so. */
234 if ( rs->sr_entry->e_private == NULL ) {
238 return SLAP_CB_CONTINUE;
242 * Search specific response that strips entryDN from entries
245 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
247 assert( op->o_tag == LDAP_REQ_SEARCH );
249 /* if in error, don't proceed any further */
250 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
254 if ( rs->sr_type == REP_SEARCH ) {
255 Attribute **ap = &rs->sr_entry->e_attrs;
257 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
258 /* will be generated later by frontend
259 * (a cleaner solution would be that
260 * the frontend checks if it already exists */
261 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
268 /* there SHOULD be one only! */
273 return SLAP_CB_CONTINUE;
275 } else if ( rs->sr_type == REP_SEARCHREF ) {
276 /* if we get it here, it means the library was unable
277 * to chase the referral... */
279 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
280 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
281 switch ( get_continuationBehavior( op ) ) {
282 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
283 op->o_callback->sc_private = LDAP_CH_ERR;
284 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
290 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
291 return SLAP_CB_CONTINUE;
293 } else if ( rs->sr_type == REP_RESULT ) {
294 /* back-ldap tried to send result */
295 op->o_callback->sc_private = LDAP_CH_RES;
302 * Dummy response that simply traces if back-ldap tried to send
303 * anything to the client
306 ldap_chain_cb_response( Operation *op, SlapReply *rs )
308 /* if in error, don't proceed any further */
309 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
313 if ( rs->sr_type == REP_RESULT ) {
314 switch ( rs->sr_err ) {
315 case LDAP_COMPARE_TRUE:
316 case LDAP_COMPARE_FALSE:
317 if ( op->o_tag != LDAP_REQ_COMPARE ) {
323 op->o_callback->sc_private = LDAP_CH_RES;
327 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
328 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
329 switch ( get_continuationBehavior( op ) ) {
330 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
331 op->o_callback->sc_private = LDAP_CH_ERR;
332 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
338 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
345 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
347 /* strip the entryDN attribute, but keep returning results */
348 (void)ldap_chain_cb_search_response( op, rs );
351 return SLAP_CB_CONTINUE;
358 int ( *op_f )( Operation *op, SlapReply *rs ),
361 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
362 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
363 ldapinfo_t li = { 0 }, *lip = NULL;
364 struct berval bvuri[ 2 ] = { { 0 } };
366 /* NOTE: returned if ref is empty... */
369 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
370 LDAPControl **ctrls = NULL;
372 (void)chaining_control_add( lc, op, &ctrls );
373 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
376 for ( ; !BER_BVISNULL( ref ); ref++ ) {
381 /* We're setting the URI of the first referral;
382 * what if there are more?
384 Document: draft-ietf-ldapbis-protocol-27.txt
388 If the client wishes to progress the operation, it MUST follow the
389 referral by contacting one of the supported services. If multiple
390 URIs are present, the client assumes that any supported URI may be
391 used to progress the operation.
393 * so we actually need to follow exactly one,
394 * and we can assume any is fine.
397 /* parse reference and use
398 * proto://[host][:port]/ only */
399 rc = ldap_url_parse_ext( ref->bv_val, &srv );
400 if ( rc != LDAP_URL_SUCCESS ) {
406 /* remove DN essentially because later on
407 * ldap_initialize() will parse the URL
408 * as a comma-separated URL list */
409 save_dn = srv->lud_dn;
411 srv->lud_scope = LDAP_SCOPE_DEFAULT;
412 li.li_uri = ldap_url_desc2str( srv );
413 srv->lud_dn = save_dn;
414 ldap_free_urldesc( srv );
416 if ( li.li_uri == NULL ) {
422 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
424 /* Searches for a ldapinfo in the avl tree */
425 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
426 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
427 (caddr_t)&li, ldap_chain_uri_cmp );
428 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
431 op->o_bd->be_private = (void *)lip;
434 rc = ldap_chain_db_init_one( op->o_bd );
438 lip = (ldapinfo_t *)op->o_bd->be_private;
439 lip->li_uri = li.li_uri;
440 lip->li_bvuri = bvuri;
441 rc = ldap_chain_db_open_one( op->o_bd );
443 (void)ldap_chain_db_destroy_one( op->o_bd );
447 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
448 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
449 if ( avl_insert( &lc->lc_lai.lai_tree,
450 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
452 /* someone just inserted another;
453 * don't bother, use this and then
457 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
464 rc = ( *op_f )( op, rs );
467 ldap_memfree( li.li_uri );
472 lip->li_bvuri = NULL;
473 (void)ldap_chain_db_close_one( op->o_bd );
474 (void)ldap_chain_db_destroy_one( op->o_bd );
477 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
482 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
483 (void)chaining_control_remove( op, &ctrls );
484 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
490 ldap_chain_response( Operation *op, SlapReply *rs )
492 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
493 void *private = op->o_bd->be_private;
494 slap_callback *sc = op->o_callback,
499 struct berval ndn = op->o_ndn;
501 int sr_err = rs->sr_err;
502 slap_reply_t sr_type = rs->sr_type;
503 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
504 slap_mask_t chain_mask = 0;
505 ber_len_t chain_shift = 0;
506 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
508 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
509 return SLAP_CB_CONTINUE;
512 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
513 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
514 switch ( get_resolveBehavior( op ) ) {
515 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
516 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
517 return SLAP_CB_CONTINUE;
520 chain_mask = SLAP_CH_RESOLVE_MASK;
521 chain_shift = SLAP_CH_RESOLVE_SHIFT;
525 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
526 switch ( get_continuationBehavior( op ) ) {
527 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
528 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
529 return SLAP_CB_CONTINUE;
532 chain_mask = SLAP_CH_CONTINUATION_MASK;
533 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
537 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
540 * TODO: add checks on who/when chain operations; e.g.:
541 * a) what identities are authorized
542 * b) what request DN (e.g. only chain requests rooted at <DN>)
543 * c) what referral URIs
544 * d) what protocol scheme (e.g. only ldaps://)
548 matched = rs->sr_matched;
549 rs->sr_matched = NULL;
553 /* we need this to know if back-ldap returned any result */
554 sc2.sc_response = ldap_chain_cb_response;
555 op->o_callback = &sc2;
557 /* Chaining can be performed by a privileged user on behalf
558 * of normal users, using the ProxyAuthz control, by exploiting
559 * the identity assertion feature of back-ldap; see idassert-*
560 * directives in slapd-ldap(5).
562 * FIXME: the idassert-authcDN is one, will it be fine regardless
563 * of the URI we obtain from the referral?
566 switch ( op->o_tag ) {
567 case LDAP_REQ_BIND: {
568 struct berval rndn = op->o_req_ndn;
569 Connection *conn = op->o_conn;
571 /* FIXME: can we really get a referral for binds? */
572 op->o_req_ndn = slap_empty_bv;
574 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
575 op->o_req_ndn = rndn;
581 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
584 case LDAP_REQ_DELETE:
585 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
588 case LDAP_REQ_MODRDN:
589 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
592 case LDAP_REQ_MODIFY:
593 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
596 case LDAP_REQ_COMPARE:
597 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
598 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
603 case LDAP_REQ_SEARCH:
604 if ( rs->sr_type == REP_SEARCHREF ) {
605 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
606 ldapinfo_t li = { 0 }, *lip = NULL;
607 struct berval bvuri[ 2 ] = { { 0 } };
609 struct berval *curr = ref,
611 ondn = op->o_req_ndn;
613 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
614 LDAPControl **ctrls = NULL;
616 (void)chaining_control_add( lc, op, &ctrls );
617 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
619 rs->sr_type = REP_SEARCH;
621 sc2.sc_response = ldap_chain_cb_search_response;
623 /* if we parse the URI then by no means
624 * we can cache stuff or reuse connections,
625 * because in back-ldap there's no caching
626 * based on the URI value, which is supposed
627 * to be set once for all (correct?) */
629 for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
634 /* parse reference and use
635 * proto://[host][:port]/ only */
636 rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
637 if ( rc != LDAP_URL_SUCCESS ) {
639 rs->sr_err = LDAP_OTHER;
643 /* remove DN essentially because later on
644 * ldap_initialize() will parse the URL
645 * as a comma-separated URL list */
646 save_dn = srv->lud_dn;
648 srv->lud_scope = LDAP_SCOPE_DEFAULT;
649 li.li_uri = ldap_url_desc2str( srv );
650 if ( li.li_uri != NULL ) {
651 ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
653 ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
657 srv->lud_dn = save_dn;
658 ldap_free_urldesc( srv );
660 if ( li.li_uri == NULL ) {
662 rs->sr_err = LDAP_OTHER;
666 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
668 /* Searches for a ldapinfo in the avl tree */
669 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
670 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
671 (caddr_t)&li, ldap_chain_uri_cmp );
672 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
675 op->o_bd->be_private = (void *)lip;
678 /* if none is found, create a temporary... */
679 rc = ldap_chain_db_init_one( op->o_bd );
683 lip = (ldapinfo_t *)op->o_bd->be_private;
684 lip->li_uri = li.li_uri;
685 lip->li_bvuri = bvuri;
686 rc = ldap_chain_db_open_one( op->o_bd );
688 (void)ldap_chain_db_destroy_one( op->o_bd );
692 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
693 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
694 if ( avl_insert( &lc->lc_lai.lai_tree,
695 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
697 /* someone just inserted another;
698 * don't bother, use this and then
702 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
709 /* FIXME: should we also copy filter and scope?
710 * according to RFC3296, no */
711 rc = lback->bi_op_search( op, rs );
714 ldap_memfree( li.li_uri );
717 op->o_tmpfree( op->o_req_dn.bv_val,
719 op->o_tmpfree( op->o_req_ndn.bv_val,
724 lip->li_bvuri = NULL;
725 (void)ldap_chain_db_close_one( op->o_bd );
726 (void)ldap_chain_db_destroy_one( op->o_bd );
729 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
736 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
737 (void)chaining_control_remove( op, &ctrls );
738 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
741 op->o_req_ndn = ondn;
742 rs->sr_type = REP_SEARCHREF;
745 if ( rc != LDAP_SUCCESS ) {
746 /* couldn't chase any of the referrals */
747 rc = SLAP_CB_CONTINUE;
751 /* we might get here before any database actually
752 * performed a search; in those cases, we need
753 * to check limits, to make sure safe defaults
755 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
756 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
759 rc = SLAP_CB_CONTINUE;
764 case LDAP_REQ_EXTENDED:
765 rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
766 /* FIXME: ldap_back_extended() by design
767 * doesn't send result; frontend is expected
769 /* FIXME: what aboit chaining? */
770 if ( rc != SLAPD_ABANDON ) {
771 send_ldap_extended( op, rs );
774 sc2.sc_private = LDAP_CH_RES;
778 rc = SLAP_CB_CONTINUE;
788 /* slapd-ldap sent response */
789 assert( sc2.sc_private == LDAP_CH_RES );
793 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
794 if ( sc2.sc_private == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
798 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
799 case LDAP_CHAINING_REQUIRED:
801 op->o_callback = NULL;
802 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
803 "operation cannot be completed without chaining" );
807 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
808 rc = SLAP_CB_CONTINUE;
810 rs->sr_type = sr_type;
811 rs->sr_matched = matched;
813 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
816 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
819 if ( sc2.sc_private == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
820 op->o_callback = NULL;
821 rc = rs->sr_err = slap_map_api2result( rs );
822 send_ldap_result( op, rs );
827 rs->sr_type = sr_type;
828 rs->sr_matched = matched;
830 op->o_bd->be_private = private;
837 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
839 ldap_chain_parse_ctrl(
845 str2chain( const char *s )
847 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
848 return LDAP_CHAINING_PREFERRED;
850 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
851 return LDAP_CHAINING_REQUIRED;
853 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
854 return LDAP_REFERRALS_PREFERRED;
856 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
857 return LDAP_REFERRALS_REQUIRED;
862 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
875 static ConfigDriver chain_cf_gen;
876 static ConfigCfAdd chain_cfadd;
877 static ConfigLDAPadd chain_ldadd;
879 static ConfigTable chaincfg[] = {
880 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
881 { "chain-chaining", "args",
882 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
883 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
884 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
885 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
886 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
887 { "chain-cache-uri", "TRUE/FALSE",
888 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
889 "( OLcfgOvAt:3.2 NAME 'olcCacheURI' "
890 "DESC 'Enables caching of URIs not present in configuration' "
891 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
892 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
895 static ConfigOCs chainocs[] = {
897 "NAME 'olcChainConfig' "
898 "DESC 'Chain configuration' "
899 "SUP olcOverlayConfig "
901 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
902 "olcChainingBehavior $ "
903 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
906 Cft_Overlay, chaincfg, NULL, chain_cfadd },
908 "NAME 'olcChainDatabase' "
909 "DESC 'Chain remote server configuration' "
911 Cft_Misc, chaincfg, chain_ldadd },
916 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
923 AttributeDescription *ad = NULL;
929 if ( p->ce_type != Cft_Overlay
931 || p->ce_bi->bi_cf_ocs != chainocs )
933 return LDAP_CONSTRAINT_VIOLATION;
936 on = (slap_overinst *)p->ce_bi;
937 lc = (ldap_chain_t *)on->on_bi.bi_private;
939 assert( ca->be == NULL );
940 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
942 ca->be->bd_info = (BackendInfo *)on;
944 rc = slap_str2ad( "olcDbURI", &ad, &text );
945 assert( rc == LDAP_SUCCESS );
947 at = attr_find( e->e_attrs, ad );
948 if ( lc->lc_common_li == NULL && at != NULL ) {
949 /* FIXME: we should generate an empty default entry
950 * if none is supplied */
951 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
952 "first underlying database \"%s\" "
953 "cannot contain attribute \"%s\".\n",
954 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
955 rc = LDAP_CONSTRAINT_VIOLATION;
958 } else if ( lc->lc_common_li != NULL && at == NULL ) {
959 /* FIXME: we should generate an empty default entry
960 * if none is supplied */
961 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
962 "subsequent underlying database \"%s\" "
963 "must contain attribute \"%s\".\n",
964 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
965 rc = LDAP_CONSTRAINT_VIOLATION;
969 if ( lc->lc_common_li == NULL ) {
970 rc = ldap_chain_db_init_common( ca->be );
973 rc = ldap_chain_db_init_one( ca->be );
977 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
978 "unable to init %sunderlying database \"%s\".\n",
979 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
980 return LDAP_CONSTRAINT_VIOLATION;
983 li = ca->be->be_private;
985 if ( lc->lc_common_li == NULL ) {
986 lc->lc_common_li = li;
988 } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
989 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
991 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
992 "database \"%s\" insert failed.\n",
993 e->e_name.bv_val, 0, 0 );
994 rc = LDAP_CONSTRAINT_VIOLATION;
999 if ( rc != LDAP_SUCCESS ) {
1000 (void)ldap_chain_db_destroy_one( ca->be );
1008 typedef struct ldap_chain_cfadd_apply_t {
1014 } ldap_chain_cfadd_apply_t;
1017 ldap_chain_cfadd_apply( void *datum, void *arg )
1019 ldapinfo_t *li = (ldapinfo_t *)datum;
1020 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1024 /* FIXME: should not hardcode "olcDatabase" here */
1025 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1026 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1027 bv.bv_val = lca->ca->msg;
1029 lca->ca->be->be_private = (void *)li;
1030 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1031 &bv, lback->bi_cf_ocs, &chainocs[1] );
1039 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1041 CfEntryInfo *pe = p->e_private;
1042 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1043 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1044 void *priv = (void *)ca->be->be_private;
1046 if ( lback->bi_cf_ocs ) {
1047 ldap_chain_cfadd_apply_t lca = { 0 };
1055 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1057 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1058 &lca, 1, AVL_INORDER );
1060 ca->be->be_private = priv;
1066 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1067 static slap_verbmasks chaining_mode[] = {
1068 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1069 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1070 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1071 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1074 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1077 chain_cf_gen( ConfigArgs *c )
1079 slap_overinst *on = (slap_overinst *)c->bi;
1080 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1084 if ( c->op == SLAP_CONFIG_EMIT ) {
1086 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1088 struct berval resolve = BER_BVNULL,
1089 continuation = BER_BVNULL;
1091 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1095 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1096 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1098 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1100 + STRLENOF( "continuation=" ) + continuation.bv_len;
1101 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1102 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1103 "resolve=%s continuation=%s",
1104 resolve.bv_val, continuation.bv_val );
1106 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1107 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1108 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1109 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1110 " critical", STRLENOF( " critical" ) + 1 );
1111 c->value_bv.bv_len += STRLENOF( " critical" );
1116 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1119 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1128 } else if ( c->op == LDAP_MOD_DELETE ) {
1134 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1145 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1146 char **argv = c->argv;
1148 BerElementBuffer berbuf;
1149 BerElement *ber = (BerElement *)&berbuf;
1153 Operation op = { 0 };
1154 SlapReply rs = { 0 };
1156 lc->lc_chaining_ctrlflag = 0;
1158 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1159 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1160 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1161 if ( resolve == -1 ) {
1162 Debug( LDAP_DEBUG_ANY, "%s: "
1163 "illegal <resolve> value %s "
1164 "in \"chain-chaining>\".\n",
1165 c->log, argv[ 0 ], 0 );
1169 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1170 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1171 if ( continuation == -1 ) {
1172 Debug( LDAP_DEBUG_ANY, "%s: "
1173 "illegal <continuation> value %s "
1174 "in \"chain-chaining\".\n",
1175 c->log, argv[ 0 ], 0 );
1179 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1183 Debug( LDAP_DEBUG_ANY, "%s: "
1184 "unknown option in \"chain-chaining\".\n",
1190 if ( resolve != -1 || continuation != -1 ) {
1193 if ( resolve == -1 ) {
1195 resolve = SLAP_CHAINING_DEFAULT;
1198 ber_init2( ber, NULL, LBER_USE_DER );
1200 err = ber_printf( ber, "{e" /* } */, resolve );
1203 Debug( LDAP_DEBUG_ANY, "%s: "
1204 "chaining behavior control encoding error!\n",
1209 if ( continuation > -1 ) {
1210 err = ber_printf( ber, "e", continuation );
1213 Debug( LDAP_DEBUG_ANY, "%s: "
1214 "chaining behavior control encoding error!\n",
1220 err = ber_printf( ber, /* { */ "N}" );
1223 Debug( LDAP_DEBUG_ANY, "%s: "
1224 "chaining behavior control encoding error!\n",
1229 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1230 exit( EXIT_FAILURE );
1234 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1237 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1238 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1240 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1242 Debug( LDAP_DEBUG_ANY, "%s: "
1243 "unable to parse chaining control%s%s.\n",
1244 c->log, rs.sr_text ? ": " : "",
1245 rs.sr_text ? rs.sr_text : "" );
1249 lc->lc_chaining_ctrlflag = op.o_chaining;
1251 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1254 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1255 Debug( LDAP_DEBUG_ANY, "%s: "
1256 "\"chaining\" control unsupported (ignored).\n",
1258 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1262 if ( c->value_int ) {
1263 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1265 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1280 slap_overinst *on = (slap_overinst *)be->bd_info;
1281 ldap_chain_t *lc = NULL;
1283 if ( lback == NULL ) {
1284 lback = backend_info( "ldap" );
1286 if ( lback == NULL ) {
1291 lc = ch_malloc( sizeof( ldap_chain_t ) );
1295 memset( lc, 0, sizeof( ldap_chain_t ) );
1297 on->on_bi.bi_private = (void *)lc;
1303 ldap_chain_db_config(
1310 slap_overinst *on = (slap_overinst *)be->bd_info;
1311 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1313 int rc = SLAP_CONF_UNKNOWN;
1315 if ( lc->lc_common_li == NULL ) {
1316 void *be_private = be->be_private;
1317 ldap_chain_db_init_common( be );
1318 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1319 be->be_private = be_private;
1322 /* Something for the chain database? */
1323 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1324 char *save_argv0 = argv[ 0 ];
1325 BackendInfo *bd_info = be->bd_info;
1326 void *be_private = be->be_private;
1327 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1328 static char *allowed_argv[] = {
1329 /* special: put URI here, so in the meanwhile
1330 * it detects whether a new URI is being provided */
1336 /* FIXME: maybe rebind-as-user should be allowed
1337 * only within known URIs... */
1344 int which_argv = -1;
1346 argv[ 0 ] += STRLENOF( "chain-" );
1348 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1349 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1354 if ( allowed_argv[ which_argv ] == NULL ) {
1357 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1358 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1359 "\"%s\" only allowed within a URI directive.\n.",
1360 fname, lineno, argv[ 0 ] );
1365 if ( which_argv == 0 ) {
1366 rc = ldap_chain_db_init_one( be );
1368 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1369 "underlying slapd-ldap initialization failed.\n.",
1373 lc->lc_cfg_li = be->be_private;
1376 /* TODO: add checks on what other slapd-ldap(5) args
1377 * should be put in the template; this is not quite
1378 * harmful, because attributes that shouldn't don't
1379 * get actually used, but the user should at least
1383 be->bd_info = lback;
1384 be->be_private = (void *)lc->lc_cfg_li;
1385 be->be_cf_ocs = lback->bi_cf_ocs;
1387 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1389 argv[ 0 ] = save_argv0;
1390 be->be_cf_ocs = be_cf_ocs;
1391 be->be_private = be_private;
1392 be->bd_info = bd_info;
1394 if ( which_argv == 0 ) {
1400 db.be_private = (void *)lc->lc_cfg_li;
1401 ldap_chain_db_destroy_one( &db );
1402 lc->lc_cfg_li = NULL;
1405 if ( lc->lc_cfg_li->li_bvuri == NULL
1406 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1407 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1409 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1410 "no URI list allowed in slapo-chain.\n",
1413 goto private_destroy;
1416 if ( avl_insert( &lc->lc_lai.lai_tree,
1417 (caddr_t)lc->lc_cfg_li,
1418 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1420 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1421 "duplicate URI in slapo-chain.\n",
1424 goto private_destroy;
1441 typedef struct ldap_chain_db_apply_t {
1444 } ldap_chain_db_apply_t;
1447 ldap_chain_db_apply( void *datum, void *arg )
1449 ldapinfo_t *li = (ldapinfo_t *)datum;
1450 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1452 lca->be->be_private = (void *)li;
1454 return lca->func( lca->be );
1463 slap_overinst *on = (slap_overinst *)be->bd_info;
1464 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1469 BI_db_func *func = (&lback->bi_db_open)[ which ];
1471 if ( func != NULL && lc->lc_common_li != NULL ) {
1475 db.be_private = lc->lc_common_li;
1483 if ( lc->lc_lai.lai_tree != NULL ) {
1484 ldap_chain_db_apply_t lca;
1489 rc = avl_apply( lc->lc_lai.lai_tree,
1490 ldap_chain_db_apply, (void *)&lca,
1491 1, AVL_INORDER ) != AVL_NOMORE;
1503 slap_overinst *on = (slap_overinst *) be->bd_info;
1504 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1506 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1509 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1513 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1515 if ( lc->lc_common_li == NULL ) {
1516 void *be_private = be->be_private;
1517 ldap_chain_db_init_common( be );
1518 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1519 be->be_private = be_private;
1522 return ldap_chain_db_func( be, db_open );
1526 ldap_chain_db_close(
1529 return ldap_chain_db_func( be, db_close );
1533 ldap_chain_db_destroy(
1536 slap_overinst *on = (slap_overinst *) be->bd_info;
1537 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1541 rc = ldap_chain_db_func( be, db_destroy );
1544 avl_free( lc->lc_lai.lai_tree, NULL );
1552 * inits one instance of the slapd-ldap backend, and stores
1553 * the private info in be_private of the arg
1556 ldap_chain_db_init_common(
1559 BackendInfo *bi = be->bd_info;
1562 be->bd_info = lback;
1563 be->be_private = NULL;
1564 t = lback->bi_db_init( be );
1574 * inits one instance of the slapd-ldap backend, stores
1575 * the private info in be_private of the arg and fills
1576 * selected fields with data from the template.
1578 * NOTE: add checks about the other fields of the template,
1579 * which are ignored and SHOULD NOT be configured by the user.
1582 ldap_chain_db_init_one(
1585 slap_overinst *on = (slap_overinst *)be->bd_info;
1586 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1588 BackendInfo *bi = be->bd_info;
1593 be->bd_info = lback;
1594 be->be_private = NULL;
1595 t = lback->bi_db_init( be );
1599 li = (ldapinfo_t *)be->be_private;
1601 /* copy common data */
1602 li->li_nretries = lc->lc_common_li->li_nretries;
1603 li->li_flags = lc->lc_common_li->li_flags;
1604 li->li_version = lc->lc_common_li->li_version;
1605 for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
1606 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1613 typedef struct ldap_chain_conn_apply_t {
1616 } ldap_chain_conn_apply_t;
1619 ldap_chain_conn_apply( void *datum, void *arg )
1621 ldapinfo_t *li = (ldapinfo_t *)datum;
1622 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1624 lca->be->be_private = (void *)li;
1626 return lback->bi_connection_destroy( lca->be, lca->conn );
1630 ldap_chain_connection_destroy(
1635 slap_overinst *on = (slap_overinst *) be->bd_info;
1636 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1637 void *private = be->be_private;
1638 ldap_chain_conn_apply_t lca;
1641 be->be_private = NULL;
1644 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1645 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1646 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1647 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1648 be->be_private = private;
1653 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1655 ldap_chain_parse_ctrl(
1665 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1666 rs->sr_text = "Chaining behavior control specified multiple times";
1667 return LDAP_PROTOCOL_ERROR;
1670 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1671 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1672 return LDAP_PROTOCOL_ERROR;
1675 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1676 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1681 /* Parse the control value
1682 * ChainingBehavior ::= SEQUENCE {
1683 * resolveBehavior Behavior OPTIONAL,
1684 * continuationBehavior Behavior OPTIONAL }
1686 * Behavior :: = ENUMERATED {
1687 * chainingPreferred (0),
1688 * chainingRequired (1),
1689 * referralsPreferred (2),
1690 * referralsRequired (3) }
1693 ber = ber_init( &ctrl->ldctl_value );
1695 rs->sr_text = "internal error";
1699 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1700 /* FIXME: since the whole SEQUENCE is optional,
1701 * should we accept no enumerations at all? */
1702 if ( tag != LBER_ENUMERATED ) {
1703 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1704 return LDAP_PROTOCOL_ERROR;
1707 switch ( behavior ) {
1708 case LDAP_CHAINING_PREFERRED:
1709 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1712 case LDAP_CHAINING_REQUIRED:
1713 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1716 case LDAP_REFERRALS_PREFERRED:
1717 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1720 case LDAP_REFERRALS_REQUIRED:
1721 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1725 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1726 return LDAP_PROTOCOL_ERROR;
1729 tag = ber_peek_tag( ber, &len );
1730 if ( tag == LBER_ENUMERATED ) {
1731 tag = ber_scanf( ber, "e", &behavior );
1732 if ( tag == LBER_ERROR ) {
1733 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1734 return LDAP_PROTOCOL_ERROR;
1738 if ( tag == LBER_DEFAULT ) {
1739 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1742 switch ( behavior ) {
1743 case LDAP_CHAINING_PREFERRED:
1744 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1747 case LDAP_CHAINING_REQUIRED:
1748 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1751 case LDAP_REFERRALS_PREFERRED:
1752 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1755 case LDAP_REFERRALS_REQUIRED:
1756 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1760 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1761 return LDAP_PROTOCOL_ERROR;
1765 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1766 rs->sr_text = "Chaining behavior control: decoding error";
1767 return LDAP_PROTOCOL_ERROR;
1770 (void) ber_free( ber, 1 );
1773 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1774 ? SLAP_CONTROL_CRITICAL
1775 : SLAP_CONTROL_NONCRITICAL );
1777 return LDAP_SUCCESS;
1779 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1781 static slap_overinst ldapchain;
1784 chain_initialize( void )
1788 /* Make sure we don't exceed the bits reserved for userland */
1789 config_check_userland( CH_LAST );
1791 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1792 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1793 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1794 ldap_chain_parse_ctrl, &sc_chainingBehavior );
1795 if ( rc != LDAP_SUCCESS ) {
1796 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1797 "unable to register chaining behavior control: %d.\n",
1801 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1803 ldapchain.on_bi.bi_type = "chain";
1804 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1805 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1806 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1807 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
1808 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1810 /* ... otherwise the underlying backend's function would be called,
1811 * likely passing an invalid entry; on the contrary, the requested
1812 * operational attributes should have been returned while chasing
1813 * the referrals. This all in all is a bit messy, because part
1814 * of the operational attributes are generated by the backend;
1815 * part by the frontend; back-ldap should receive all the available
1816 * ones from the remote server, but then, on its own, it strips those
1817 * it assumes will be (re)generated by the frontend (e.g.
1818 * subschemaSubentry.) */
1819 ldapchain.on_bi.bi_operational = ldap_chain_operational;
1821 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1823 ldapchain.on_response = ldap_chain_response;
1825 ldapchain.on_bi.bi_cf_ocs = chainocs;
1827 rc = config_register_schema( chaincfg, chainocs );
1832 return overlay_register( &ldapchain );