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 */
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 #define ldap_chain_db_open_one(be) (lback)->bi_db_open( (be) )
114 #define ldap_chain_db_close_one(be) (0)
115 #define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
117 typedef struct ldap_chain_cb_t {
118 ldap_chain_status_t lb_status;
139 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
141 chaining_control_add(
144 LDAPControl ***oldctrlsp )
146 LDAPControl **ctrls = NULL;
149 *oldctrlsp = op->o_ctrls;
151 /* default chaining control not defined */
152 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
156 /* already present */
157 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
161 /* FIXME: check other incompatibilities */
163 /* add to other controls */
165 for ( c = 0; op->o_ctrls[ c ]; c++ )
169 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
170 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
172 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
173 ctrls[ c + 1 ] = op->o_ctrls[ c ];
176 ctrls[ c + 1 ] = NULL;
180 op->o_chaining = lc->lc_chaining_ctrlflag;
186 chaining_control_remove(
188 LDAPControl ***oldctrlsp )
190 LDAPControl **oldctrls = *oldctrlsp;
192 /* we assume that the first control is the chaining control
193 * added by the chain overlay, so it's the only one we explicitly
195 if ( op->o_ctrls != oldctrls ) {
196 assert( op->o_ctrls != NULL );
197 assert( op->o_ctrls[ 0 ] != NULL );
202 op->o_ctrls = oldctrls;
209 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
212 ldap_chain_uri_cmp( const void *c1, const void *c2 )
214 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
215 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
217 assert( li1->li_bvuri != NULL );
218 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
219 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
221 assert( li2->li_bvuri != NULL );
222 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
223 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
225 /* If local DNs don't match, it is definitely not a match */
226 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
230 ldap_chain_uri_dup( void *c1, void *c2 )
232 ldapinfo_t *li1 = (ldapinfo_t *)c1;
233 ldapinfo_t *li2 = (ldapinfo_t *)c2;
235 assert( li1->li_bvuri != NULL );
236 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
237 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
239 assert( li2->li_bvuri != NULL );
240 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
241 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
243 /* Cannot have more than one shared session with same DN */
244 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
252 * Search specific response that strips entryDN from entries
255 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
257 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
259 assert( op->o_tag == LDAP_REQ_SEARCH );
261 /* if in error, don't proceed any further */
262 if ( lb->lb_status == LDAP_CH_ERR ) {
266 if ( rs->sr_type == REP_SEARCH ) {
267 Attribute **ap = &rs->sr_entry->e_attrs;
269 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
270 /* will be generated later by frontend
271 * (a cleaner solution would be that
272 * the frontend checks if it already exists */
273 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
280 /* there SHOULD be one only! */
285 /* tell the frontend not to add generated
286 * operational attributes */
287 rs->sr_flags |= REP_NO_OPERATIONALS;
289 return SLAP_CB_CONTINUE;
291 } else if ( rs->sr_type == REP_SEARCHREF ) {
292 /* if we get it here, it means the library was unable
293 * to chase the referral... */
294 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
295 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
298 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
299 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
300 switch ( get_continuationBehavior( op ) ) {
301 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
302 lb->lb_status = LDAP_CH_ERR;
303 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
309 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
310 return SLAP_CB_CONTINUE;
312 } else if ( rs->sr_type == REP_RESULT ) {
313 if ( rs->sr_err == LDAP_REFERRAL
314 && lb->lb_depth < lb->lb_lc->lc_max_depth
315 && rs->sr_ref != NULL )
317 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
320 /* back-ldap tried to send result */
321 lb->lb_status = LDAP_CH_RES;
328 * Dummy response that simply traces if back-ldap tried to send
329 * anything to the client
332 ldap_chain_cb_response( Operation *op, SlapReply *rs )
334 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
336 /* if in error, don't proceed any further */
337 if ( lb->lb_status == LDAP_CH_ERR ) {
341 if ( rs->sr_type == REP_RESULT ) {
343 switch ( rs->sr_err ) {
344 case LDAP_COMPARE_TRUE:
345 case LDAP_COMPARE_FALSE:
346 if ( op->o_tag != LDAP_REQ_COMPARE ) {
352 lb->lb_status = LDAP_CH_RES;
356 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
357 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
361 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
362 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
363 switch ( get_continuationBehavior( op ) ) {
364 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
365 lb->lb_status = LDAP_CH_ERR;
366 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
372 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
379 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
381 /* strip the entryDN attribute, but keep returning results */
382 (void)ldap_chain_cb_search_response( op, rs );
385 return SLAP_CB_CONTINUE;
396 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
397 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
398 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
399 ldapinfo_t li = { 0 }, *lip = NULL;
400 struct berval bvuri[ 2 ] = { { 0 } };
402 /* NOTE: returned if ref is empty... */
406 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
407 LDAPControl **ctrls = NULL;
409 (void)chaining_control_add( lc, op, &ctrls );
410 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
414 for ( ; !BER_BVISNULL( ref ); ref++ ) {
419 /* We're setting the URI of the first referral;
420 * what if there are more?
422 Document: draft-ietf-ldapbis-protocol-27.txt
426 If the client wishes to progress the operation, it MUST follow the
427 referral by contacting one of the supported services. If multiple
428 URIs are present, the client assumes that any supported URI may be
429 used to progress the operation.
431 * so we actually need to follow exactly one,
432 * and we can assume any is fine.
435 /* parse reference and use
436 * proto://[host][:port]/ only */
437 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
438 if ( rc != LDAP_URL_SUCCESS ) {
444 /* remove DN essentially because later on
445 * ldap_initialize() will parse the URL
446 * as a comma-separated URL list */
447 save_dn = srv->lud_dn;
449 srv->lud_scope = LDAP_SCOPE_DEFAULT;
450 li.li_uri = ldap_url_desc2str( srv );
451 srv->lud_dn = save_dn;
452 ldap_free_urldesc( srv );
454 if ( li.li_uri == NULL ) {
460 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
462 /* Searches for a ldapinfo in the avl tree */
463 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
464 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
465 (caddr_t)&li, ldap_chain_uri_cmp );
466 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
469 op->o_bd->be_private = (void *)lip;
472 rc = ldap_chain_db_init_one( op->o_bd );
476 lip = (ldapinfo_t *)op->o_bd->be_private;
477 lip->li_uri = li.li_uri;
478 lip->li_bvuri = bvuri;
479 rc = ldap_chain_db_open_one( op->o_bd );
482 lip->li_bvuri = NULL;
483 (void)ldap_chain_db_destroy_one( op->o_bd );
487 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
488 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
489 if ( avl_insert( &lc->lc_lai.lai_tree,
490 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
492 /* someone just inserted another;
493 * don't bother, use this and then
497 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
505 lb->lb_depth = depth + 1;
509 /* note the first error */
510 if ( first_rc == -1 ) {
515 ldap_memfree( li.li_uri );
520 lip->li_bvuri = NULL;
521 (void)ldap_chain_db_close_one( op->o_bd );
522 (void)ldap_chain_db_destroy_one( op->o_bd );
525 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
530 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
531 (void)chaining_control_remove( op, &ctrls );
532 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
534 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
549 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
550 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
551 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
552 ldapinfo_t li = { 0 }, *lip = NULL;
553 struct berval bvuri[ 2 ] = { { 0 } };
555 struct berval odn = op->o_req_dn,
556 ondn = op->o_req_ndn;
557 slap_response *save_response = op->o_callback->sc_response;
562 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
563 LDAPControl **ctrls = NULL;
565 (void)chaining_control_add( lc, op, &ctrls );
566 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
568 rs->sr_type = REP_SEARCH;
570 op->o_callback->sc_response = ldap_chain_cb_search_response;
572 /* if we parse the URI then by no means
573 * we can cache stuff or reuse connections,
574 * because in back-ldap there's no caching
575 * based on the URI value, which is supposed
576 * to be set once for all (correct?) */
578 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
583 /* parse reference and use
584 * proto://[host][:port]/ only */
585 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
586 if ( rc != LDAP_URL_SUCCESS ) {
588 rs->sr_err = LDAP_OTHER;
592 /* remove DN essentially because later on
593 * ldap_initialize() will parse the URL
594 * as a comma-separated URL list */
595 save_dn = srv->lud_dn;
597 srv->lud_scope = LDAP_SCOPE_DEFAULT;
598 li.li_uri = ldap_url_desc2str( srv );
599 if ( li.li_uri != NULL ) {
600 ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
602 ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
606 srv->lud_dn = save_dn;
607 ldap_free_urldesc( srv );
609 if ( li.li_uri == NULL ) {
611 rs->sr_err = LDAP_OTHER;
615 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
617 /* Searches for a ldapinfo in the avl tree */
618 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
619 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
620 (caddr_t)&li, ldap_chain_uri_cmp );
621 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
624 op->o_bd->be_private = (void *)lip;
627 /* if none is found, create a temporary... */
628 rc = ldap_chain_db_init_one( op->o_bd );
632 lip = (ldapinfo_t *)op->o_bd->be_private;
633 lip->li_uri = li.li_uri;
634 lip->li_bvuri = bvuri;
635 rc = ldap_chain_db_open_one( op->o_bd );
638 lip->li_bvuri = NULL;
639 (void)ldap_chain_db_destroy_one( op->o_bd );
643 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
644 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
645 if ( avl_insert( &lc->lc_lai.lai_tree,
646 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
648 /* someone just inserted another;
649 * don't bother, use this and then
653 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
660 lb->lb_op_f = lback->bi_op_search;
661 lb->lb_depth = depth + 1;
663 /* FIXME: should we also copy filter and scope?
664 * according to RFC3296, no */
665 rc = lback->bi_op_search( op, rs );
666 if ( first_rc == -1 ) {
671 ldap_memfree( li.li_uri );
674 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
675 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
679 lip->li_bvuri = NULL;
680 (void)ldap_chain_db_close_one( op->o_bd );
681 (void)ldap_chain_db_destroy_one( op->o_bd );
684 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
691 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
692 (void)chaining_control_remove( op, &ctrls );
693 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
696 op->o_req_ndn = ondn;
697 op->o_callback->sc_response = save_response;
698 rs->sr_type = REP_SEARCHREF;
701 if ( rc != LDAP_SUCCESS ) {
702 /* couldn't chase any of the referrals */
703 if ( first_rc != -1 ) {
707 rc = SLAP_CB_CONTINUE;
715 ldap_chain_response( Operation *op, SlapReply *rs )
717 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
718 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
719 void *private = op->o_bd->be_private;
720 ldap_chain_cb_t lb = { 0 };
721 slap_callback *sc = op->o_callback,
726 struct berval ndn = op->o_ndn;
728 int sr_err = rs->sr_err;
729 slap_reply_t sr_type = rs->sr_type;
730 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
731 slap_mask_t chain_mask = 0;
732 ber_len_t chain_shift = 0;
733 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
735 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
736 return SLAP_CB_CONTINUE;
739 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
740 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
741 switch ( get_resolveBehavior( op ) ) {
742 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
743 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
744 return SLAP_CB_CONTINUE;
747 chain_mask = SLAP_CH_RESOLVE_MASK;
748 chain_shift = SLAP_CH_RESOLVE_SHIFT;
752 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
753 switch ( get_continuationBehavior( op ) ) {
754 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
755 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
756 return SLAP_CB_CONTINUE;
759 chain_mask = SLAP_CH_CONTINUATION_MASK;
760 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
764 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
767 * TODO: add checks on who/when chain operations; e.g.:
768 * a) what identities are authorized
769 * b) what request DN (e.g. only chain requests rooted at <DN>)
770 * c) what referral URIs
771 * d) what protocol scheme (e.g. only ldaps://)
775 matched = rs->sr_matched;
776 rs->sr_matched = NULL;
780 /* we need this to know if back-ldap returned any result */
782 sc2.sc_private = &lb;
783 sc2.sc_response = ldap_chain_cb_response;
784 op->o_callback = &sc2;
786 /* Chaining can be performed by a privileged user on behalf
787 * of normal users, using the ProxyAuthz control, by exploiting
788 * the identity assertion feature of back-ldap; see idassert-*
789 * directives in slapd-ldap(5).
791 * FIXME: the idassert-authcDN is one, will it be fine regardless
792 * of the URI we obtain from the referral?
795 switch ( op->o_tag ) {
796 case LDAP_REQ_BIND: {
797 struct berval rndn = op->o_req_ndn;
798 Connection *conn = op->o_conn;
800 /* FIXME: can we really get a referral for binds? */
801 op->o_req_ndn = slap_empty_bv;
803 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
804 op->o_req_ndn = rndn;
810 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
813 case LDAP_REQ_DELETE:
814 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
817 case LDAP_REQ_MODRDN:
818 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
821 case LDAP_REQ_MODIFY:
822 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
825 case LDAP_REQ_COMPARE:
826 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
827 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
832 case LDAP_REQ_SEARCH:
833 if ( rs->sr_type == REP_SEARCHREF ) {
834 rc = ldap_chain_search( op, rs, ref, 0 );
837 /* we might get here before any database actually
838 * performed a search; in those cases, we need
839 * to check limits, to make sure safe defaults
841 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
842 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
845 rc = SLAP_CB_CONTINUE;
850 case LDAP_REQ_EXTENDED:
851 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
852 /* FIXME: ldap_back_extended() by design
853 * doesn't send result; frontend is expected
855 /* FIXME: what about chaining? */
856 if ( rc != SLAPD_ABANDON ) {
857 send_ldap_extended( op, rs );
860 lb.lb_status = LDAP_CH_RES;
864 rc = SLAP_CB_CONTINUE;
874 /* slapd-ldap sent response */
875 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
876 /* FIXME: should we send response? */
877 Debug( LDAP_DEBUG_ANY,
878 "%s: ldap_chain_response: "
879 "overlay should have sent result.\n",
880 op->o_log_prefix, 0, 0 );
885 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
886 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
890 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
891 case LDAP_CHAINING_REQUIRED:
893 op->o_callback = NULL;
894 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
895 "operation cannot be completed without chaining" );
899 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
900 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
902 rs->sr_type = sr_type;
905 rc = SLAP_CB_CONTINUE;
907 rs->sr_type = sr_type;
908 rs->sr_matched = matched;
911 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
914 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
917 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
918 op->o_callback = NULL;
919 rc = rs->sr_err = slap_map_api2result( rs );
920 send_ldap_result( op, rs );
925 rs->sr_type = sr_type;
926 rs->sr_matched = matched;
928 op->o_bd->be_private = private;
935 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
937 ldap_chain_parse_ctrl(
943 str2chain( const char *s )
945 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
946 return LDAP_CHAINING_PREFERRED;
948 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
949 return LDAP_CHAINING_REQUIRED;
951 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
952 return LDAP_REFERRALS_PREFERRED;
954 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
955 return LDAP_REFERRALS_REQUIRED;
960 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
975 static ConfigDriver chain_cf_gen;
976 static ConfigCfAdd chain_cfadd;
977 static ConfigLDAPadd chain_ldadd;
979 static ConfigTable chaincfg[] = {
980 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
981 { "chain-chaining", "args",
982 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
983 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
984 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
985 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
986 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
987 { "chain-cache-uri", "TRUE/FALSE",
988 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
989 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
990 "DESC 'Enables caching of URIs not present in configuration' "
991 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
992 { "chain-max-depth", "args",
993 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
994 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
995 "DESC 'max referral depth' "
997 "EQUALITY integerMatch "
998 "SINGLE-VALUE )", NULL, NULL },
999 { "chain-return-error", "TRUE/FALSE",
1000 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1001 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1002 "DESC 'Errors are returned instead of the original referral' "
1003 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1004 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1007 static ConfigOCs chainocs[] = {
1008 { "( OLcfgOvOc:3.1 "
1009 "NAME 'olcChainConfig' "
1010 "DESC 'Chain configuration' "
1011 "SUP olcOverlayConfig "
1013 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1014 "olcChainingBehavior $ "
1015 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1016 "olcChainCacheURI $ "
1017 "olcChainMaxReferralDepth $ "
1018 "olcChainReturnError "
1020 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1021 { "( OLcfgOvOc:3.2 "
1022 "NAME 'olcChainDatabase' "
1023 "DESC 'Chain remote server configuration' "
1025 Cft_Misc, chaincfg, chain_ldadd },
1030 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1037 AttributeDescription *ad = NULL;
1043 if ( p->ce_type != Cft_Overlay
1045 || p->ce_bi->bi_cf_ocs != chainocs )
1047 return LDAP_CONSTRAINT_VIOLATION;
1050 on = (slap_overinst *)p->ce_bi;
1051 lc = (ldap_chain_t *)on->on_bi.bi_private;
1053 assert( ca->be == NULL );
1054 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1056 ca->be->bd_info = (BackendInfo *)on;
1058 rc = slap_str2ad( "olcDbURI", &ad, &text );
1059 assert( rc == LDAP_SUCCESS );
1061 at = attr_find( e->e_attrs, ad );
1062 if ( lc->lc_common_li == NULL && at != NULL ) {
1063 /* FIXME: we should generate an empty default entry
1064 * if none is supplied */
1065 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1066 "first underlying database \"%s\" "
1067 "cannot contain attribute \"%s\".\n",
1068 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1069 rc = LDAP_CONSTRAINT_VIOLATION;
1072 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1073 /* FIXME: we should generate an empty default entry
1074 * if none is supplied */
1075 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1076 "subsequent underlying database \"%s\" "
1077 "must contain attribute \"%s\".\n",
1078 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1079 rc = LDAP_CONSTRAINT_VIOLATION;
1083 if ( lc->lc_common_li == NULL ) {
1084 rc = ldap_chain_db_init_common( ca->be );
1087 rc = ldap_chain_db_init_one( ca->be );
1091 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1092 "unable to init %sunderlying database \"%s\".\n",
1093 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1094 return LDAP_CONSTRAINT_VIOLATION;
1097 li = ca->be->be_private;
1099 if ( lc->lc_common_li == NULL ) {
1100 lc->lc_common_li = li;
1102 } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1103 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1105 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1106 "database \"%s\" insert failed.\n",
1107 e->e_name.bv_val, 0, 0 );
1108 rc = LDAP_CONSTRAINT_VIOLATION;
1113 if ( rc != LDAP_SUCCESS ) {
1114 (void)ldap_chain_db_destroy_one( ca->be );
1122 typedef struct ldap_chain_cfadd_apply_t {
1128 } ldap_chain_cfadd_apply_t;
1131 ldap_chain_cfadd_apply( void *datum, void *arg )
1133 ldapinfo_t *li = (ldapinfo_t *)datum;
1134 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1138 /* FIXME: should not hardcode "olcDatabase" here */
1139 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1140 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1141 bv.bv_val = lca->ca->msg;
1143 lca->ca->be->be_private = (void *)li;
1144 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1145 &bv, lback->bi_cf_ocs, &chainocs[1] );
1153 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1155 CfEntryInfo *pe = p->e_private;
1156 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1157 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1158 void *priv = (void *)ca->be->be_private;
1160 if ( lback->bi_cf_ocs ) {
1161 ldap_chain_cfadd_apply_t lca = { 0 };
1169 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1171 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1172 &lca, 1, AVL_INORDER );
1174 ca->be->be_private = priv;
1180 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1181 static slap_verbmasks chaining_mode[] = {
1182 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1183 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1184 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1185 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1188 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1191 chain_cf_gen( ConfigArgs *c )
1193 slap_overinst *on = (slap_overinst *)c->bi;
1194 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1198 if ( c->op == SLAP_CONFIG_EMIT ) {
1200 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1202 struct berval resolve = BER_BVNULL,
1203 continuation = BER_BVNULL;
1205 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1209 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1210 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1212 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1214 + STRLENOF( "continuation=" ) + continuation.bv_len;
1215 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1216 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1217 "resolve=%s continuation=%s",
1218 resolve.bv_val, continuation.bv_val );
1220 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1221 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1222 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1223 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1224 " critical", STRLENOF( " critical" ) + 1 );
1225 c->value_bv.bv_len += STRLENOF( " critical" );
1230 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1233 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1237 c->value_int = lc->lc_max_depth;
1241 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1250 } else if ( c->op == LDAP_MOD_DELETE ) {
1256 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1264 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1275 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1276 char **argv = c->argv;
1278 BerElementBuffer berbuf;
1279 BerElement *ber = (BerElement *)&berbuf;
1283 Operation op = { 0 };
1284 SlapReply rs = { 0 };
1286 lc->lc_chaining_ctrlflag = 0;
1288 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1289 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1290 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1291 if ( resolve == -1 ) {
1292 Debug( LDAP_DEBUG_ANY, "%s: "
1293 "illegal <resolve> value %s "
1294 "in \"chain-chaining>\".\n",
1295 c->log, argv[ 0 ], 0 );
1299 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1300 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1301 if ( continuation == -1 ) {
1302 Debug( LDAP_DEBUG_ANY, "%s: "
1303 "illegal <continuation> value %s "
1304 "in \"chain-chaining\".\n",
1305 c->log, argv[ 0 ], 0 );
1309 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1313 Debug( LDAP_DEBUG_ANY, "%s: "
1314 "unknown option in \"chain-chaining\".\n",
1320 if ( resolve != -1 || continuation != -1 ) {
1323 if ( resolve == -1 ) {
1325 resolve = SLAP_CHAINING_DEFAULT;
1328 ber_init2( ber, NULL, LBER_USE_DER );
1330 err = ber_printf( ber, "{e" /* } */, resolve );
1333 Debug( LDAP_DEBUG_ANY, "%s: "
1334 "chaining behavior control encoding error!\n",
1339 if ( continuation > -1 ) {
1340 err = ber_printf( ber, "e", continuation );
1343 Debug( LDAP_DEBUG_ANY, "%s: "
1344 "chaining behavior control encoding error!\n",
1350 err = ber_printf( ber, /* { */ "N}" );
1353 Debug( LDAP_DEBUG_ANY, "%s: "
1354 "chaining behavior control encoding error!\n",
1359 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1360 exit( EXIT_FAILURE );
1364 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1367 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1368 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1370 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1372 Debug( LDAP_DEBUG_ANY, "%s: "
1373 "unable to parse chaining control%s%s.\n",
1374 c->log, rs.sr_text ? ": " : "",
1375 rs.sr_text ? rs.sr_text : "" );
1379 lc->lc_chaining_ctrlflag = op.o_chaining;
1381 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1384 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1385 Debug( LDAP_DEBUG_ANY, "%s: "
1386 "\"chaining\" control unsupported (ignored).\n",
1388 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1392 if ( c->value_int ) {
1393 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1395 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1400 if ( c->value_int < 0 ) {
1401 snprintf( c->msg, sizeof( c->msg ),
1402 "<%s> invalid max referral depth %d",
1403 c->argv[0], c->value_int );
1404 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1405 c->log, c->msg, 0 );
1409 lc->lc_max_depth = c->value_int;
1412 if ( c->value_int ) {
1413 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1415 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1430 slap_overinst *on = (slap_overinst *)be->bd_info;
1431 ldap_chain_t *lc = NULL;
1433 if ( lback == NULL ) {
1434 lback = backend_info( "ldap" );
1436 if ( lback == NULL ) {
1441 lc = ch_malloc( sizeof( ldap_chain_t ) );
1445 memset( lc, 0, sizeof( ldap_chain_t ) );
1446 lc->lc_max_depth = 1;
1447 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1449 on->on_bi.bi_private = (void *)lc;
1455 ldap_chain_db_config(
1462 slap_overinst *on = (slap_overinst *)be->bd_info;
1463 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1465 int rc = SLAP_CONF_UNKNOWN;
1467 if ( lc->lc_common_li == NULL ) {
1468 void *be_private = be->be_private;
1469 ldap_chain_db_init_common( be );
1470 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1471 be->be_private = be_private;
1474 /* Something for the chain database? */
1475 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1476 char *save_argv0 = argv[ 0 ];
1477 BackendInfo *bd_info = be->bd_info;
1478 void *be_private = be->be_private;
1479 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1480 static char *allowed_argv[] = {
1481 /* special: put URI here, so in the meanwhile
1482 * it detects whether a new URI is being provided */
1488 /* FIXME: maybe rebind-as-user should be allowed
1489 * only within known URIs... */
1496 int which_argv = -1;
1498 argv[ 0 ] += STRLENOF( "chain-" );
1500 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1501 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1506 if ( allowed_argv[ which_argv ] == NULL ) {
1509 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1510 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1511 "\"%s\" only allowed within a URI directive.\n.",
1512 fname, lineno, argv[ 0 ] );
1517 if ( which_argv == 0 ) {
1518 rc = ldap_chain_db_init_one( be );
1520 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1521 "underlying slapd-ldap initialization failed.\n.",
1525 lc->lc_cfg_li = be->be_private;
1528 /* TODO: add checks on what other slapd-ldap(5) args
1529 * should be put in the template; this is not quite
1530 * harmful, because attributes that shouldn't don't
1531 * get actually used, but the user should at least
1535 be->bd_info = lback;
1536 be->be_private = (void *)lc->lc_cfg_li;
1537 be->be_cf_ocs = lback->bi_cf_ocs;
1539 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1541 argv[ 0 ] = save_argv0;
1542 be->be_cf_ocs = be_cf_ocs;
1543 be->be_private = be_private;
1544 be->bd_info = bd_info;
1546 if ( which_argv == 0 ) {
1552 db.be_private = (void *)lc->lc_cfg_li;
1553 ldap_chain_db_destroy_one( &db );
1554 lc->lc_cfg_li = NULL;
1557 if ( lc->lc_cfg_li->li_bvuri == NULL
1558 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1559 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1561 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1562 "no URI list allowed in slapo-chain.\n",
1565 goto private_destroy;
1568 if ( avl_insert( &lc->lc_lai.lai_tree,
1569 (caddr_t)lc->lc_cfg_li,
1570 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1572 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1573 "duplicate URI in slapo-chain.\n",
1576 goto private_destroy;
1593 typedef struct ldap_chain_db_apply_t {
1596 } ldap_chain_db_apply_t;
1599 ldap_chain_db_apply( void *datum, void *arg )
1601 ldapinfo_t *li = (ldapinfo_t *)datum;
1602 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1604 lca->be->be_private = (void *)li;
1606 return lca->func( lca->be );
1615 slap_overinst *on = (slap_overinst *)be->bd_info;
1616 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1621 BI_db_func *func = (&lback->bi_db_open)[ which ];
1623 if ( func != NULL && lc->lc_common_li != NULL ) {
1627 db.be_private = lc->lc_common_li;
1635 if ( lc->lc_lai.lai_tree != NULL ) {
1636 ldap_chain_db_apply_t lca;
1641 rc = avl_apply( lc->lc_lai.lai_tree,
1642 ldap_chain_db_apply, (void *)&lca,
1643 1, AVL_INORDER ) != AVL_NOMORE;
1655 slap_overinst *on = (slap_overinst *) be->bd_info;
1656 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1658 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1661 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1665 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1667 if ( lc->lc_common_li == NULL ) {
1668 void *be_private = be->be_private;
1669 ldap_chain_db_init_common( be );
1670 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1671 be->be_private = be_private;
1674 return ldap_chain_db_func( be, db_open );
1678 ldap_chain_db_close(
1681 return ldap_chain_db_func( be, db_close );
1685 ldap_chain_db_destroy(
1688 slap_overinst *on = (slap_overinst *) be->bd_info;
1689 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1693 rc = ldap_chain_db_func( be, db_destroy );
1696 avl_free( lc->lc_lai.lai_tree, NULL );
1697 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1705 * inits one instance of the slapd-ldap backend, and stores
1706 * the private info in be_private of the arg
1709 ldap_chain_db_init_common(
1712 BackendInfo *bi = be->bd_info;
1716 be->bd_info = lback;
1717 be->be_private = NULL;
1718 t = lback->bi_db_init( be );
1722 li = (ldapinfo_t *)be->be_private;
1723 li->li_urllist_f = NULL;
1724 li->li_urllist_p = NULL;
1731 * inits one instance of the slapd-ldap backend, stores
1732 * the private info in be_private of the arg and fills
1733 * selected fields with data from the template.
1735 * NOTE: add checks about the other fields of the template,
1736 * which are ignored and SHOULD NOT be configured by the user.
1739 ldap_chain_db_init_one(
1742 slap_overinst *on = (slap_overinst *)be->bd_info;
1743 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1745 BackendInfo *bi = be->bd_info;
1750 be->bd_info = lback;
1751 be->be_private = NULL;
1752 t = lback->bi_db_init( be );
1756 li = (ldapinfo_t *)be->be_private;
1757 li->li_urllist_f = NULL;
1758 li->li_urllist_p = NULL;
1760 /* copy common data */
1761 li->li_nretries = lc->lc_common_li->li_nretries;
1762 li->li_flags = lc->lc_common_li->li_flags;
1763 li->li_version = lc->lc_common_li->li_version;
1764 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1765 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1772 typedef struct ldap_chain_conn_apply_t {
1775 } ldap_chain_conn_apply_t;
1778 ldap_chain_conn_apply( void *datum, void *arg )
1780 ldapinfo_t *li = (ldapinfo_t *)datum;
1781 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1783 lca->be->be_private = (void *)li;
1785 return lback->bi_connection_destroy( lca->be, lca->conn );
1789 ldap_chain_connection_destroy(
1794 slap_overinst *on = (slap_overinst *) be->bd_info;
1795 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1796 void *private = be->be_private;
1797 ldap_chain_conn_apply_t lca;
1800 be->be_private = NULL;
1803 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1804 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1805 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1806 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1807 be->be_private = private;
1812 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1814 ldap_chain_parse_ctrl(
1824 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1825 rs->sr_text = "Chaining behavior control specified multiple times";
1826 return LDAP_PROTOCOL_ERROR;
1829 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1830 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1831 return LDAP_PROTOCOL_ERROR;
1834 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1835 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1840 /* Parse the control value
1841 * ChainingBehavior ::= SEQUENCE {
1842 * resolveBehavior Behavior OPTIONAL,
1843 * continuationBehavior Behavior OPTIONAL }
1845 * Behavior :: = ENUMERATED {
1846 * chainingPreferred (0),
1847 * chainingRequired (1),
1848 * referralsPreferred (2),
1849 * referralsRequired (3) }
1852 ber = ber_init( &ctrl->ldctl_value );
1854 rs->sr_text = "internal error";
1858 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1859 /* FIXME: since the whole SEQUENCE is optional,
1860 * should we accept no enumerations at all? */
1861 if ( tag != LBER_ENUMERATED ) {
1862 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1863 return LDAP_PROTOCOL_ERROR;
1866 switch ( behavior ) {
1867 case LDAP_CHAINING_PREFERRED:
1868 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1871 case LDAP_CHAINING_REQUIRED:
1872 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1875 case LDAP_REFERRALS_PREFERRED:
1876 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1879 case LDAP_REFERRALS_REQUIRED:
1880 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1884 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1885 return LDAP_PROTOCOL_ERROR;
1888 tag = ber_peek_tag( ber, &len );
1889 if ( tag == LBER_ENUMERATED ) {
1890 tag = ber_scanf( ber, "e", &behavior );
1891 if ( tag == LBER_ERROR ) {
1892 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1893 return LDAP_PROTOCOL_ERROR;
1897 if ( tag == LBER_DEFAULT ) {
1898 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1901 switch ( behavior ) {
1902 case LDAP_CHAINING_PREFERRED:
1903 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1906 case LDAP_CHAINING_REQUIRED:
1907 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1910 case LDAP_REFERRALS_PREFERRED:
1911 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1914 case LDAP_REFERRALS_REQUIRED:
1915 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1919 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1920 return LDAP_PROTOCOL_ERROR;
1924 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1925 rs->sr_text = "Chaining behavior control: decoding error";
1926 return LDAP_PROTOCOL_ERROR;
1929 (void) ber_free( ber, 1 );
1932 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1933 ? SLAP_CONTROL_CRITICAL
1934 : SLAP_CONTROL_NONCRITICAL );
1936 return LDAP_SUCCESS;
1938 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1940 static slap_overinst ldapchain;
1943 chain_initialize( void )
1947 /* Make sure we don't exceed the bits reserved for userland */
1948 config_check_userland( CH_LAST );
1950 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1951 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1952 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1953 ldap_chain_parse_ctrl, &sc_chainingBehavior );
1954 if ( rc != LDAP_SUCCESS ) {
1955 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1956 "unable to register chaining behavior control: %d.\n",
1960 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1962 ldapchain.on_bi.bi_type = "chain";
1963 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1964 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1965 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1966 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
1967 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1969 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1971 ldapchain.on_response = ldap_chain_response;
1973 ldapchain.on_bi.bi_cf_ocs = chainocs;
1975 rc = config_register_schema( chaincfg, chainocs );
1980 return overlay_register( &ldapchain );