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 * Search specific response that strips entryDN from entries
226 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
228 assert( op->o_tag == LDAP_REQ_SEARCH );
230 /* if in error, don't proceed any further */
231 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
235 if ( rs->sr_type == REP_SEARCH ) {
236 Attribute **ap = &rs->sr_entry->e_attrs;
238 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
239 /* will be generated later by frontend
240 * (a cleaner solution would be that
241 * the frontend checks if it already exists */
242 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
249 /* there SHOULD be one only! */
254 /* tell the frontend not to add generated
255 * operational attributes */
256 rs->sr_flags |= REP_NO_OPERATIONALS;
258 return SLAP_CB_CONTINUE;
260 } else if ( rs->sr_type == REP_SEARCHREF ) {
261 /* if we get it here, it means the library was unable
262 * to chase the referral... */
264 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
265 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
266 switch ( get_continuationBehavior( op ) ) {
267 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
268 op->o_callback->sc_private = LDAP_CH_ERR;
269 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
275 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
276 return SLAP_CB_CONTINUE;
278 } else if ( rs->sr_type == REP_RESULT ) {
279 /* back-ldap tried to send result */
280 op->o_callback->sc_private = LDAP_CH_RES;
287 * Dummy response that simply traces if back-ldap tried to send
288 * anything to the client
291 ldap_chain_cb_response( Operation *op, SlapReply *rs )
293 /* if in error, don't proceed any further */
294 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
298 if ( rs->sr_type == REP_RESULT ) {
299 switch ( rs->sr_err ) {
300 case LDAP_COMPARE_TRUE:
301 case LDAP_COMPARE_FALSE:
302 if ( op->o_tag != LDAP_REQ_COMPARE ) {
308 op->o_callback->sc_private = LDAP_CH_RES;
312 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
313 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
314 switch ( get_continuationBehavior( op ) ) {
315 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
316 op->o_callback->sc_private = LDAP_CH_ERR;
317 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
323 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
330 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
332 /* strip the entryDN attribute, but keep returning results */
333 (void)ldap_chain_cb_search_response( op, rs );
336 return SLAP_CB_CONTINUE;
346 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
347 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
348 ldapinfo_t li = { 0 }, *lip = NULL;
349 struct berval bvuri[ 2 ] = { { 0 } };
351 /* NOTE: returned if ref is empty... */
354 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
355 LDAPControl **ctrls = NULL;
357 (void)chaining_control_add( lc, op, &ctrls );
358 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
361 for ( ; !BER_BVISNULL( ref ); ref++ ) {
366 /* We're setting the URI of the first referral;
367 * what if there are more?
369 Document: draft-ietf-ldapbis-protocol-27.txt
373 If the client wishes to progress the operation, it MUST follow the
374 referral by contacting one of the supported services. If multiple
375 URIs are present, the client assumes that any supported URI may be
376 used to progress the operation.
378 * so we actually need to follow exactly one,
379 * and we can assume any is fine.
382 /* parse reference and use
383 * proto://[host][:port]/ only */
384 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
385 if ( rc != LDAP_URL_SUCCESS ) {
391 /* remove DN essentially because later on
392 * ldap_initialize() will parse the URL
393 * as a comma-separated URL list */
394 save_dn = srv->lud_dn;
396 srv->lud_scope = LDAP_SCOPE_DEFAULT;
397 li.li_uri = ldap_url_desc2str( srv );
398 srv->lud_dn = save_dn;
399 ldap_free_urldesc( srv );
401 if ( li.li_uri == NULL ) {
407 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
409 /* Searches for a ldapinfo in the avl tree */
410 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
411 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
412 (caddr_t)&li, ldap_chain_uri_cmp );
413 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
416 op->o_bd->be_private = (void *)lip;
419 rc = ldap_chain_db_init_one( op->o_bd );
423 lip = (ldapinfo_t *)op->o_bd->be_private;
424 lip->li_uri = li.li_uri;
425 lip->li_bvuri = bvuri;
426 rc = ldap_chain_db_open_one( op->o_bd );
428 (void)ldap_chain_db_destroy_one( op->o_bd );
432 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
433 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
434 if ( avl_insert( &lc->lc_lai.lai_tree,
435 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
437 /* someone just inserted another;
438 * don't bother, use this and then
442 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
452 ldap_memfree( li.li_uri );
457 lip->li_bvuri = NULL;
458 (void)ldap_chain_db_close_one( op->o_bd );
459 (void)ldap_chain_db_destroy_one( op->o_bd );
462 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
467 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
468 (void)chaining_control_remove( op, &ctrls );
469 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
475 ldap_chain_response( Operation *op, SlapReply *rs )
477 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
478 void *private = op->o_bd->be_private;
479 slap_callback *sc = op->o_callback,
484 struct berval ndn = op->o_ndn;
486 int sr_err = rs->sr_err;
487 slap_reply_t sr_type = rs->sr_type;
488 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
489 slap_mask_t chain_mask = 0;
490 ber_len_t chain_shift = 0;
491 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
493 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
494 return SLAP_CB_CONTINUE;
497 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
498 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
499 switch ( get_resolveBehavior( op ) ) {
500 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
501 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
502 return SLAP_CB_CONTINUE;
505 chain_mask = SLAP_CH_RESOLVE_MASK;
506 chain_shift = SLAP_CH_RESOLVE_SHIFT;
510 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
511 switch ( get_continuationBehavior( op ) ) {
512 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
513 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
514 return SLAP_CB_CONTINUE;
517 chain_mask = SLAP_CH_CONTINUATION_MASK;
518 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
522 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
525 * TODO: add checks on who/when chain operations; e.g.:
526 * a) what identities are authorized
527 * b) what request DN (e.g. only chain requests rooted at <DN>)
528 * c) what referral URIs
529 * d) what protocol scheme (e.g. only ldaps://)
533 matched = rs->sr_matched;
534 rs->sr_matched = NULL;
538 /* we need this to know if back-ldap returned any result */
539 sc2.sc_response = ldap_chain_cb_response;
540 op->o_callback = &sc2;
542 /* Chaining can be performed by a privileged user on behalf
543 * of normal users, using the ProxyAuthz control, by exploiting
544 * the identity assertion feature of back-ldap; see idassert-*
545 * directives in slapd-ldap(5).
547 * FIXME: the idassert-authcDN is one, will it be fine regardless
548 * of the URI we obtain from the referral?
551 switch ( op->o_tag ) {
552 case LDAP_REQ_BIND: {
553 struct berval rndn = op->o_req_ndn;
554 Connection *conn = op->o_conn;
556 /* FIXME: can we really get a referral for binds? */
557 op->o_req_ndn = slap_empty_bv;
559 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
560 op->o_req_ndn = rndn;
566 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
569 case LDAP_REQ_DELETE:
570 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
573 case LDAP_REQ_MODRDN:
574 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
577 case LDAP_REQ_MODIFY:
578 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
581 case LDAP_REQ_COMPARE:
582 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
583 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
588 case LDAP_REQ_SEARCH:
589 if ( rs->sr_type == REP_SEARCHREF ) {
590 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
591 ldapinfo_t li = { 0 }, *lip = NULL;
592 struct berval bvuri[ 2 ] = { { 0 } };
594 struct berval *curr = ref,
596 ondn = op->o_req_ndn;
598 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
599 LDAPControl **ctrls = NULL;
601 (void)chaining_control_add( lc, op, &ctrls );
602 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
604 rs->sr_type = REP_SEARCH;
606 sc2.sc_response = ldap_chain_cb_search_response;
608 /* if we parse the URI then by no means
609 * we can cache stuff or reuse connections,
610 * because in back-ldap there's no caching
611 * based on the URI value, which is supposed
612 * to be set once for all (correct?) */
614 for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
619 /* parse reference and use
620 * proto://[host][:port]/ only */
621 rc = ldap_url_parse_ext( curr[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
622 if ( rc != LDAP_URL_SUCCESS ) {
624 rs->sr_err = LDAP_OTHER;
628 /* remove DN essentially because later on
629 * ldap_initialize() will parse the URL
630 * as a comma-separated URL list */
631 save_dn = srv->lud_dn;
633 srv->lud_scope = LDAP_SCOPE_DEFAULT;
634 li.li_uri = ldap_url_desc2str( srv );
635 if ( li.li_uri != NULL ) {
636 ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
638 ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
642 srv->lud_dn = save_dn;
643 ldap_free_urldesc( srv );
645 if ( li.li_uri == NULL ) {
647 rs->sr_err = LDAP_OTHER;
651 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
653 /* Searches for a ldapinfo in the avl tree */
654 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
655 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
656 (caddr_t)&li, ldap_chain_uri_cmp );
657 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
660 op->o_bd->be_private = (void *)lip;
663 /* if none is found, create a temporary... */
664 rc = ldap_chain_db_init_one( op->o_bd );
668 lip = (ldapinfo_t *)op->o_bd->be_private;
669 lip->li_uri = li.li_uri;
670 lip->li_bvuri = bvuri;
671 rc = ldap_chain_db_open_one( op->o_bd );
673 (void)ldap_chain_db_destroy_one( op->o_bd );
677 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
678 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
679 if ( avl_insert( &lc->lc_lai.lai_tree,
680 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
682 /* someone just inserted another;
683 * don't bother, use this and then
687 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
694 /* FIXME: should we also copy filter and scope?
695 * according to RFC3296, no */
696 rc = lback->bi_op_search( op, rs );
699 ldap_memfree( li.li_uri );
702 op->o_tmpfree( op->o_req_dn.bv_val,
704 op->o_tmpfree( op->o_req_ndn.bv_val,
709 lip->li_bvuri = NULL;
710 (void)ldap_chain_db_close_one( op->o_bd );
711 (void)ldap_chain_db_destroy_one( op->o_bd );
714 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
721 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
722 (void)chaining_control_remove( op, &ctrls );
723 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
726 op->o_req_ndn = ondn;
727 rs->sr_type = REP_SEARCHREF;
730 if ( rc != LDAP_SUCCESS ) {
731 /* couldn't chase any of the referrals */
732 rc = SLAP_CB_CONTINUE;
736 /* we might get here before any database actually
737 * performed a search; in those cases, we need
738 * to check limits, to make sure safe defaults
740 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
741 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
744 rc = SLAP_CB_CONTINUE;
749 case LDAP_REQ_EXTENDED:
750 rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
751 /* FIXME: ldap_back_extended() by design
752 * doesn't send result; frontend is expected
754 /* FIXME: what about chaining? */
755 if ( rc != SLAPD_ABANDON ) {
756 send_ldap_extended( op, rs );
759 sc2.sc_private = LDAP_CH_RES;
763 rc = SLAP_CB_CONTINUE;
773 /* slapd-ldap sent response */
774 if ( !op->o_abandon && sc2.sc_private != LDAP_CH_RES ) {
775 /* FIXME: should we send response? */
776 Debug( LDAP_DEBUG_ANY,
777 "%s: ldap_chain_response: "
778 "overlay should have sent result.\n",
779 op->o_log_prefix, 0, 0 );
784 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
785 if ( sc2.sc_private == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
789 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
790 case LDAP_CHAINING_REQUIRED:
792 op->o_callback = NULL;
793 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
794 "operation cannot be completed without chaining" );
798 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
799 rc = SLAP_CB_CONTINUE;
801 rs->sr_type = sr_type;
802 rs->sr_matched = matched;
804 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
807 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
810 if ( sc2.sc_private == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
811 op->o_callback = NULL;
812 rc = rs->sr_err = slap_map_api2result( rs );
813 send_ldap_result( op, rs );
818 rs->sr_type = sr_type;
819 rs->sr_matched = matched;
821 op->o_bd->be_private = private;
828 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
830 ldap_chain_parse_ctrl(
836 str2chain( const char *s )
838 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
839 return LDAP_CHAINING_PREFERRED;
841 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
842 return LDAP_CHAINING_REQUIRED;
844 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
845 return LDAP_REFERRALS_PREFERRED;
847 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
848 return LDAP_REFERRALS_REQUIRED;
853 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
866 static ConfigDriver chain_cf_gen;
867 static ConfigCfAdd chain_cfadd;
868 static ConfigLDAPadd chain_ldadd;
870 static ConfigTable chaincfg[] = {
871 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
872 { "chain-chaining", "args",
873 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
874 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
875 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
876 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
877 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
878 { "chain-cache-uri", "TRUE/FALSE",
879 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
880 "( OLcfgOvAt:3.2 NAME 'olcCacheURI' "
881 "DESC 'Enables caching of URIs not present in configuration' "
882 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
883 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
886 static ConfigOCs chainocs[] = {
888 "NAME 'olcChainConfig' "
889 "DESC 'Chain configuration' "
890 "SUP olcOverlayConfig "
892 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
893 "olcChainingBehavior $ "
894 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
897 Cft_Overlay, chaincfg, NULL, chain_cfadd },
899 "NAME 'olcChainDatabase' "
900 "DESC 'Chain remote server configuration' "
902 Cft_Misc, chaincfg, chain_ldadd },
907 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
914 AttributeDescription *ad = NULL;
920 if ( p->ce_type != Cft_Overlay
922 || p->ce_bi->bi_cf_ocs != chainocs )
924 return LDAP_CONSTRAINT_VIOLATION;
927 on = (slap_overinst *)p->ce_bi;
928 lc = (ldap_chain_t *)on->on_bi.bi_private;
930 assert( ca->be == NULL );
931 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
933 ca->be->bd_info = (BackendInfo *)on;
935 rc = slap_str2ad( "olcDbURI", &ad, &text );
936 assert( rc == LDAP_SUCCESS );
938 at = attr_find( e->e_attrs, ad );
939 if ( lc->lc_common_li == NULL && at != NULL ) {
940 /* FIXME: we should generate an empty default entry
941 * if none is supplied */
942 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
943 "first underlying database \"%s\" "
944 "cannot contain attribute \"%s\".\n",
945 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
946 rc = LDAP_CONSTRAINT_VIOLATION;
949 } else if ( lc->lc_common_li != NULL && at == NULL ) {
950 /* FIXME: we should generate an empty default entry
951 * if none is supplied */
952 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
953 "subsequent underlying database \"%s\" "
954 "must contain attribute \"%s\".\n",
955 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
956 rc = LDAP_CONSTRAINT_VIOLATION;
960 if ( lc->lc_common_li == NULL ) {
961 rc = ldap_chain_db_init_common( ca->be );
964 rc = ldap_chain_db_init_one( ca->be );
968 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
969 "unable to init %sunderlying database \"%s\".\n",
970 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
971 return LDAP_CONSTRAINT_VIOLATION;
974 li = ca->be->be_private;
976 if ( lc->lc_common_li == NULL ) {
977 lc->lc_common_li = li;
979 } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
980 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
982 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
983 "database \"%s\" insert failed.\n",
984 e->e_name.bv_val, 0, 0 );
985 rc = LDAP_CONSTRAINT_VIOLATION;
990 if ( rc != LDAP_SUCCESS ) {
991 (void)ldap_chain_db_destroy_one( ca->be );
999 typedef struct ldap_chain_cfadd_apply_t {
1005 } ldap_chain_cfadd_apply_t;
1008 ldap_chain_cfadd_apply( void *datum, void *arg )
1010 ldapinfo_t *li = (ldapinfo_t *)datum;
1011 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1015 /* FIXME: should not hardcode "olcDatabase" here */
1016 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1017 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1018 bv.bv_val = lca->ca->msg;
1020 lca->ca->be->be_private = (void *)li;
1021 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1022 &bv, lback->bi_cf_ocs, &chainocs[1] );
1030 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1032 CfEntryInfo *pe = p->e_private;
1033 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1034 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1035 void *priv = (void *)ca->be->be_private;
1037 if ( lback->bi_cf_ocs ) {
1038 ldap_chain_cfadd_apply_t lca = { 0 };
1046 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1048 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1049 &lca, 1, AVL_INORDER );
1051 ca->be->be_private = priv;
1057 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1058 static slap_verbmasks chaining_mode[] = {
1059 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1060 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1061 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1062 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1065 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1068 chain_cf_gen( ConfigArgs *c )
1070 slap_overinst *on = (slap_overinst *)c->bi;
1071 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1075 if ( c->op == SLAP_CONFIG_EMIT ) {
1077 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1079 struct berval resolve = BER_BVNULL,
1080 continuation = BER_BVNULL;
1082 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1086 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1087 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1089 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1091 + STRLENOF( "continuation=" ) + continuation.bv_len;
1092 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1093 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1094 "resolve=%s continuation=%s",
1095 resolve.bv_val, continuation.bv_val );
1097 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1098 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1099 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1100 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1101 " critical", STRLENOF( " critical" ) + 1 );
1102 c->value_bv.bv_len += STRLENOF( " critical" );
1107 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1110 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1119 } else if ( c->op == LDAP_MOD_DELETE ) {
1125 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1136 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1137 char **argv = c->argv;
1139 BerElementBuffer berbuf;
1140 BerElement *ber = (BerElement *)&berbuf;
1144 Operation op = { 0 };
1145 SlapReply rs = { 0 };
1147 lc->lc_chaining_ctrlflag = 0;
1149 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1150 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1151 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1152 if ( resolve == -1 ) {
1153 Debug( LDAP_DEBUG_ANY, "%s: "
1154 "illegal <resolve> value %s "
1155 "in \"chain-chaining>\".\n",
1156 c->log, argv[ 0 ], 0 );
1160 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1161 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1162 if ( continuation == -1 ) {
1163 Debug( LDAP_DEBUG_ANY, "%s: "
1164 "illegal <continuation> value %s "
1165 "in \"chain-chaining\".\n",
1166 c->log, argv[ 0 ], 0 );
1170 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1174 Debug( LDAP_DEBUG_ANY, "%s: "
1175 "unknown option in \"chain-chaining\".\n",
1181 if ( resolve != -1 || continuation != -1 ) {
1184 if ( resolve == -1 ) {
1186 resolve = SLAP_CHAINING_DEFAULT;
1189 ber_init2( ber, NULL, LBER_USE_DER );
1191 err = ber_printf( ber, "{e" /* } */, resolve );
1194 Debug( LDAP_DEBUG_ANY, "%s: "
1195 "chaining behavior control encoding error!\n",
1200 if ( continuation > -1 ) {
1201 err = ber_printf( ber, "e", continuation );
1204 Debug( LDAP_DEBUG_ANY, "%s: "
1205 "chaining behavior control encoding error!\n",
1211 err = ber_printf( ber, /* { */ "N}" );
1214 Debug( LDAP_DEBUG_ANY, "%s: "
1215 "chaining behavior control encoding error!\n",
1220 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1221 exit( EXIT_FAILURE );
1225 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1228 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1229 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1231 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1233 Debug( LDAP_DEBUG_ANY, "%s: "
1234 "unable to parse chaining control%s%s.\n",
1235 c->log, rs.sr_text ? ": " : "",
1236 rs.sr_text ? rs.sr_text : "" );
1240 lc->lc_chaining_ctrlflag = op.o_chaining;
1242 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1245 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1246 Debug( LDAP_DEBUG_ANY, "%s: "
1247 "\"chaining\" control unsupported (ignored).\n",
1249 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1253 if ( c->value_int ) {
1254 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1256 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1271 slap_overinst *on = (slap_overinst *)be->bd_info;
1272 ldap_chain_t *lc = NULL;
1274 if ( lback == NULL ) {
1275 lback = backend_info( "ldap" );
1277 if ( lback == NULL ) {
1282 lc = ch_malloc( sizeof( ldap_chain_t ) );
1286 memset( lc, 0, sizeof( ldap_chain_t ) );
1287 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1289 on->on_bi.bi_private = (void *)lc;
1295 ldap_chain_db_config(
1302 slap_overinst *on = (slap_overinst *)be->bd_info;
1303 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1305 int rc = SLAP_CONF_UNKNOWN;
1307 if ( lc->lc_common_li == NULL ) {
1308 void *be_private = be->be_private;
1309 ldap_chain_db_init_common( be );
1310 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1311 be->be_private = be_private;
1314 /* Something for the chain database? */
1315 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1316 char *save_argv0 = argv[ 0 ];
1317 BackendInfo *bd_info = be->bd_info;
1318 void *be_private = be->be_private;
1319 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1320 static char *allowed_argv[] = {
1321 /* special: put URI here, so in the meanwhile
1322 * it detects whether a new URI is being provided */
1328 /* FIXME: maybe rebind-as-user should be allowed
1329 * only within known URIs... */
1336 int which_argv = -1;
1338 argv[ 0 ] += STRLENOF( "chain-" );
1340 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1341 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1346 if ( allowed_argv[ which_argv ] == NULL ) {
1349 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1350 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1351 "\"%s\" only allowed within a URI directive.\n.",
1352 fname, lineno, argv[ 0 ] );
1357 if ( which_argv == 0 ) {
1358 rc = ldap_chain_db_init_one( be );
1360 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1361 "underlying slapd-ldap initialization failed.\n.",
1365 lc->lc_cfg_li = be->be_private;
1368 /* TODO: add checks on what other slapd-ldap(5) args
1369 * should be put in the template; this is not quite
1370 * harmful, because attributes that shouldn't don't
1371 * get actually used, but the user should at least
1375 be->bd_info = lback;
1376 be->be_private = (void *)lc->lc_cfg_li;
1377 be->be_cf_ocs = lback->bi_cf_ocs;
1379 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1381 argv[ 0 ] = save_argv0;
1382 be->be_cf_ocs = be_cf_ocs;
1383 be->be_private = be_private;
1384 be->bd_info = bd_info;
1386 if ( which_argv == 0 ) {
1392 db.be_private = (void *)lc->lc_cfg_li;
1393 ldap_chain_db_destroy_one( &db );
1394 lc->lc_cfg_li = NULL;
1397 if ( lc->lc_cfg_li->li_bvuri == NULL
1398 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1399 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1401 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1402 "no URI list allowed in slapo-chain.\n",
1405 goto private_destroy;
1408 if ( avl_insert( &lc->lc_lai.lai_tree,
1409 (caddr_t)lc->lc_cfg_li,
1410 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1412 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1413 "duplicate URI in slapo-chain.\n",
1416 goto private_destroy;
1433 typedef struct ldap_chain_db_apply_t {
1436 } ldap_chain_db_apply_t;
1439 ldap_chain_db_apply( void *datum, void *arg )
1441 ldapinfo_t *li = (ldapinfo_t *)datum;
1442 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1444 lca->be->be_private = (void *)li;
1446 return lca->func( lca->be );
1455 slap_overinst *on = (slap_overinst *)be->bd_info;
1456 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1461 BI_db_func *func = (&lback->bi_db_open)[ which ];
1463 if ( func != NULL && lc->lc_common_li != NULL ) {
1467 db.be_private = lc->lc_common_li;
1475 if ( lc->lc_lai.lai_tree != NULL ) {
1476 ldap_chain_db_apply_t lca;
1481 rc = avl_apply( lc->lc_lai.lai_tree,
1482 ldap_chain_db_apply, (void *)&lca,
1483 1, AVL_INORDER ) != AVL_NOMORE;
1495 slap_overinst *on = (slap_overinst *) be->bd_info;
1496 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1498 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1501 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1505 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1507 if ( lc->lc_common_li == NULL ) {
1508 void *be_private = be->be_private;
1509 ldap_chain_db_init_common( be );
1510 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1511 be->be_private = be_private;
1514 return ldap_chain_db_func( be, db_open );
1518 ldap_chain_db_close(
1521 return ldap_chain_db_func( be, db_close );
1525 ldap_chain_db_destroy(
1528 slap_overinst *on = (slap_overinst *) be->bd_info;
1529 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1533 rc = ldap_chain_db_func( be, db_destroy );
1536 avl_free( lc->lc_lai.lai_tree, NULL );
1537 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1545 * inits one instance of the slapd-ldap backend, and stores
1546 * the private info in be_private of the arg
1549 ldap_chain_db_init_common(
1552 BackendInfo *bi = be->bd_info;
1556 be->bd_info = lback;
1557 be->be_private = NULL;
1558 t = lback->bi_db_init( be );
1562 li = (ldapinfo_t *)be->be_private;
1563 li->li_urllist_f = NULL;
1564 li->li_urllist_p = NULL;
1571 * inits one instance of the slapd-ldap backend, stores
1572 * the private info in be_private of the arg and fills
1573 * selected fields with data from the template.
1575 * NOTE: add checks about the other fields of the template,
1576 * which are ignored and SHOULD NOT be configured by the user.
1579 ldap_chain_db_init_one(
1582 slap_overinst *on = (slap_overinst *)be->bd_info;
1583 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1585 BackendInfo *bi = be->bd_info;
1590 be->bd_info = lback;
1591 be->be_private = NULL;
1592 t = lback->bi_db_init( be );
1596 li = (ldapinfo_t *)be->be_private;
1597 li->li_urllist_f = NULL;
1598 li->li_urllist_p = NULL;
1600 /* copy common data */
1601 li->li_nretries = lc->lc_common_li->li_nretries;
1602 li->li_flags = lc->lc_common_li->li_flags;
1603 li->li_version = lc->lc_common_li->li_version;
1604 for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
1605 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1612 typedef struct ldap_chain_conn_apply_t {
1615 } ldap_chain_conn_apply_t;
1618 ldap_chain_conn_apply( void *datum, void *arg )
1620 ldapinfo_t *li = (ldapinfo_t *)datum;
1621 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1623 lca->be->be_private = (void *)li;
1625 return lback->bi_connection_destroy( lca->be, lca->conn );
1629 ldap_chain_connection_destroy(
1634 slap_overinst *on = (slap_overinst *) be->bd_info;
1635 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1636 void *private = be->be_private;
1637 ldap_chain_conn_apply_t lca;
1640 be->be_private = NULL;
1643 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1644 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1645 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1646 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1647 be->be_private = private;
1652 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1654 ldap_chain_parse_ctrl(
1664 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1665 rs->sr_text = "Chaining behavior control specified multiple times";
1666 return LDAP_PROTOCOL_ERROR;
1669 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1670 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1671 return LDAP_PROTOCOL_ERROR;
1674 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1675 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1680 /* Parse the control value
1681 * ChainingBehavior ::= SEQUENCE {
1682 * resolveBehavior Behavior OPTIONAL,
1683 * continuationBehavior Behavior OPTIONAL }
1685 * Behavior :: = ENUMERATED {
1686 * chainingPreferred (0),
1687 * chainingRequired (1),
1688 * referralsPreferred (2),
1689 * referralsRequired (3) }
1692 ber = ber_init( &ctrl->ldctl_value );
1694 rs->sr_text = "internal error";
1698 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1699 /* FIXME: since the whole SEQUENCE is optional,
1700 * should we accept no enumerations at all? */
1701 if ( tag != LBER_ENUMERATED ) {
1702 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1703 return LDAP_PROTOCOL_ERROR;
1706 switch ( behavior ) {
1707 case LDAP_CHAINING_PREFERRED:
1708 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1711 case LDAP_CHAINING_REQUIRED:
1712 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1715 case LDAP_REFERRALS_PREFERRED:
1716 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1719 case LDAP_REFERRALS_REQUIRED:
1720 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1724 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1725 return LDAP_PROTOCOL_ERROR;
1728 tag = ber_peek_tag( ber, &len );
1729 if ( tag == LBER_ENUMERATED ) {
1730 tag = ber_scanf( ber, "e", &behavior );
1731 if ( tag == LBER_ERROR ) {
1732 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1733 return LDAP_PROTOCOL_ERROR;
1737 if ( tag == LBER_DEFAULT ) {
1738 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1741 switch ( behavior ) {
1742 case LDAP_CHAINING_PREFERRED:
1743 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1746 case LDAP_CHAINING_REQUIRED:
1747 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1750 case LDAP_REFERRALS_PREFERRED:
1751 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1754 case LDAP_REFERRALS_REQUIRED:
1755 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1759 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1760 return LDAP_PROTOCOL_ERROR;
1764 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1765 rs->sr_text = "Chaining behavior control: decoding error";
1766 return LDAP_PROTOCOL_ERROR;
1769 (void) ber_free( ber, 1 );
1772 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1773 ? SLAP_CONTROL_CRITICAL
1774 : SLAP_CONTROL_NONCRITICAL );
1776 return LDAP_SUCCESS;
1778 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1780 static slap_overinst ldapchain;
1783 chain_initialize( void )
1787 /* Make sure we don't exceed the bits reserved for userland */
1788 config_check_userland( CH_LAST );
1790 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1791 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1792 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1793 ldap_chain_parse_ctrl, &sc_chainingBehavior );
1794 if ( rc != LDAP_SUCCESS ) {
1795 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1796 "unable to register chaining behavior control: %d.\n",
1800 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1802 ldapchain.on_bi.bi_type = "chain";
1803 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1804 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1805 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1806 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
1807 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1809 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1811 ldapchain.on_response = ldap_chain_response;
1813 ldapchain.on_bi.bi_cf_ocs = chainocs;
1815 rc = config_register_schema( chaincfg, chainocs );
1820 return overlay_register( &ldapchain );