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>
32 #include "back-ldap.h"
35 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
36 #define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED
37 #define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT
38 #define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT)
39 #define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
40 #define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
41 #define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
42 #define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
43 #define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
44 #define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2)
45 #define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT)
46 #define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
47 #define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
48 #define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
49 #define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
50 #define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
52 #define o_chaining o_ctrlflag[sc_chainingBehavior]
53 #define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK)
54 #define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
55 #define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
56 #define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
58 static int sc_chainingBehavior;
59 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
65 } ldap_chain_status_t;
66 static BackendInfo *lback;
68 typedef struct ldap_chain_t {
70 * A "template" ldapinfo_t gets all common configuration items;
71 * then, for each configured URI, an entry is created in the tree;
72 * all the specific configuration items get in the current URI
75 * Then, for each referral, extract the URI and lookup the
76 * related structure. If configured to do so, allow URIs
77 * not found in the structure to create a temporary one
78 * that chains anonymously; maybe it can also be added to
79 * the tree? Should be all configurable.
82 /* "common" configuration info (anything occurring before an "uri") */
83 ldapinfo_t *lc_common_li;
85 /* current configuration info */
86 ldapinfo_t *lc_cfg_li;
88 /* tree of configured[/generated?] "uri" info */
89 ldap_avl_info_t lc_lai;
91 /* max depth in nested referrals chaining */
95 #define LDAP_CHAIN_F_NONE (0x00U)
96 #define LDAP_CHAIN_F_CHAINING (0x01U)
97 #define LDAP_CHAIN_F_CACHE_URI (0x02U)
98 #define LDAP_CHAIN_F_RETURN_ERR (0x04U)
100 #define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
101 #define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
102 #define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
103 #define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
105 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
106 LDAPControl lc_chaining_ctrl;
107 char lc_chaining_ctrlflag;
108 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
111 static int ldap_chain_db_init_common( BackendDB *be );
112 static int ldap_chain_db_init_one( BackendDB *be );
113 static int ldap_chain_db_open_one( BackendDB *be );
114 #define ldap_chain_db_close_one(be) (0)
115 #define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
117 typedef struct ldap_chain_cb_t {
118 ldap_chain_status_t lb_status;
139 static slap_overinst ldapchain;
141 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
143 chaining_control_add(
146 LDAPControl ***oldctrlsp )
148 LDAPControl **ctrls = NULL;
151 *oldctrlsp = op->o_ctrls;
153 /* default chaining control not defined */
154 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
158 /* already present */
159 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
163 /* FIXME: check other incompatibilities */
165 /* add to other controls */
167 for ( c = 0; op->o_ctrls[ c ]; c++ )
171 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
172 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
174 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
175 ctrls[ c + 1 ] = op->o_ctrls[ c ];
178 ctrls[ c + 1 ] = NULL;
182 op->o_chaining = lc->lc_chaining_ctrlflag;
188 chaining_control_remove(
190 LDAPControl ***oldctrlsp )
192 LDAPControl **oldctrls = *oldctrlsp;
194 /* we assume that the first control is the chaining control
195 * added by the chain overlay, so it's the only one we explicitly
197 if ( op->o_ctrls != oldctrls ) {
198 assert( op->o_ctrls != NULL );
199 assert( op->o_ctrls[ 0 ] != NULL );
204 op->o_ctrls = oldctrls;
211 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
214 ldap_chain_uri_cmp( const void *c1, const void *c2 )
216 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
217 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
219 assert( li1->li_bvuri != NULL );
220 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
221 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
223 assert( li2->li_bvuri != NULL );
224 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
225 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
227 /* If local DNs don't match, it is definitely not a match */
228 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
232 ldap_chain_uri_dup( void *c1, void *c2 )
234 ldapinfo_t *li1 = (ldapinfo_t *)c1;
235 ldapinfo_t *li2 = (ldapinfo_t *)c2;
237 assert( li1->li_bvuri != NULL );
238 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
239 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
241 assert( li2->li_bvuri != NULL );
242 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
243 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
245 /* Cannot have more than one shared session with same DN */
246 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
254 * Search specific response that strips entryDN from entries
257 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
259 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
261 assert( op->o_tag == LDAP_REQ_SEARCH );
263 /* if in error, don't proceed any further */
264 if ( lb->lb_status == LDAP_CH_ERR ) {
268 if ( rs->sr_type == REP_SEARCH ) {
269 Attribute **ap = &rs->sr_entry->e_attrs;
271 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
272 /* will be generated later by frontend
273 * (a cleaner solution would be that
274 * the frontend checks if it already exists */
275 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
282 /* there SHOULD be one only! */
287 /* tell the frontend not to add generated
288 * operational attributes */
289 rs->sr_flags |= REP_NO_OPERATIONALS;
291 return SLAP_CB_CONTINUE;
293 } else if ( rs->sr_type == REP_SEARCHREF ) {
294 /* if we get it here, it means the library was unable
295 * to chase the referral... */
296 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
297 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
300 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
301 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
302 switch ( get_continuationBehavior( op ) ) {
303 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
304 lb->lb_status = LDAP_CH_ERR;
305 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
311 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
312 return SLAP_CB_CONTINUE;
314 } else if ( rs->sr_type == REP_RESULT ) {
315 if ( rs->sr_err == LDAP_REFERRAL
316 && lb->lb_depth < lb->lb_lc->lc_max_depth
317 && rs->sr_ref != NULL )
319 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
322 /* back-ldap tried to send result */
323 lb->lb_status = LDAP_CH_RES;
330 * Dummy response that simply traces if back-ldap tried to send
331 * anything to the client
334 ldap_chain_cb_response( Operation *op, SlapReply *rs )
336 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
338 /* if in error, don't proceed any further */
339 if ( lb->lb_status == LDAP_CH_ERR ) {
343 if ( rs->sr_type == REP_RESULT ) {
345 switch ( rs->sr_err ) {
346 case LDAP_COMPARE_TRUE:
347 case LDAP_COMPARE_FALSE:
348 if ( op->o_tag != LDAP_REQ_COMPARE ) {
354 lb->lb_status = LDAP_CH_RES;
358 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
359 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
363 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
364 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
365 switch ( get_continuationBehavior( op ) ) {
366 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
367 lb->lb_status = LDAP_CH_ERR;
368 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
374 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
381 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
383 /* strip the entryDN attribute, but keep returning results */
384 (void)ldap_chain_cb_search_response( op, rs );
387 return SLAP_CB_CONTINUE;
398 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
399 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
400 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
401 ldapinfo_t li = { 0 }, *lip = NULL;
402 struct berval bvuri[ 2 ] = { { 0 } };
404 /* NOTE: returned if ref is empty... */
408 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
409 LDAPControl **ctrls = NULL;
411 (void)chaining_control_add( lc, op, &ctrls );
412 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
416 for ( ; !BER_BVISNULL( ref ); ref++ ) {
421 /* We're setting the URI of the first referral;
422 * what if there are more?
424 Document: draft-ietf-ldapbis-protocol-27.txt
428 If the client wishes to progress the operation, it MUST follow the
429 referral by contacting one of the supported services. If multiple
430 URIs are present, the client assumes that any supported URI may be
431 used to progress the operation.
433 * so we actually need to follow exactly one,
434 * and we can assume any is fine.
437 /* parse reference and use
438 * proto://[host][:port]/ only */
439 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
440 if ( rc != LDAP_URL_SUCCESS ) {
446 /* remove DN essentially because later on
447 * ldap_initialize() will parse the URL
448 * as a comma-separated URL list */
449 save_dn = srv->lud_dn;
451 srv->lud_scope = LDAP_SCOPE_DEFAULT;
452 li.li_uri = ldap_url_desc2str( srv );
453 srv->lud_dn = save_dn;
454 ldap_free_urldesc( srv );
456 if ( li.li_uri == NULL ) {
462 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
464 /* Searches for a ldapinfo in the avl tree */
465 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
466 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
467 (caddr_t)&li, ldap_chain_uri_cmp );
468 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
471 op->o_bd->be_private = (void *)lip;
474 rc = ldap_chain_db_init_one( op->o_bd );
478 lip = (ldapinfo_t *)op->o_bd->be_private;
479 lip->li_uri = li.li_uri;
480 lip->li_bvuri = bvuri;
481 rc = ldap_chain_db_open_one( op->o_bd );
484 lip->li_bvuri = NULL;
485 (void)ldap_chain_db_destroy_one( op->o_bd );
489 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
490 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
491 if ( avl_insert( &lc->lc_lai.lai_tree,
492 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
494 /* someone just inserted another;
495 * don't bother, use this and then
499 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
507 lb->lb_depth = depth + 1;
511 /* note the first error */
512 if ( first_rc == -1 ) {
517 ldap_memfree( li.li_uri );
522 lip->li_bvuri = NULL;
523 (void)ldap_chain_db_close_one( op->o_bd );
524 (void)ldap_chain_db_destroy_one( op->o_bd );
527 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
532 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
533 (void)chaining_control_remove( op, &ctrls );
534 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
536 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
551 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
552 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
553 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
554 ldapinfo_t li = { 0 }, *lip = NULL;
555 struct berval bvuri[ 2 ] = { { 0 } };
557 struct berval odn = op->o_req_dn,
558 ondn = op->o_req_ndn;
559 slap_response *save_response = op->o_callback->sc_response;
564 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
565 LDAPControl **ctrls = NULL;
567 (void)chaining_control_add( lc, op, &ctrls );
568 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
570 rs->sr_type = REP_SEARCH;
572 op->o_callback->sc_response = ldap_chain_cb_search_response;
574 /* if we parse the URI then by no means
575 * we can cache stuff or reuse connections,
576 * because in back-ldap there's no caching
577 * based on the URI value, which is supposed
578 * to be set once for all (correct?) */
580 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
585 /* parse reference and use
586 * proto://[host][:port]/ only */
587 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
588 if ( rc != LDAP_URL_SUCCESS ) {
590 rs->sr_err = LDAP_OTHER;
594 /* remove DN essentially because later on
595 * ldap_initialize() will parse the URL
596 * as a comma-separated URL list */
597 save_dn = srv->lud_dn;
599 srv->lud_scope = LDAP_SCOPE_DEFAULT;
600 li.li_uri = ldap_url_desc2str( srv );
601 if ( li.li_uri != NULL ) {
602 ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
604 ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
608 srv->lud_dn = save_dn;
609 ldap_free_urldesc( srv );
611 if ( li.li_uri == NULL ) {
613 rs->sr_err = LDAP_OTHER;
617 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
619 /* Searches for a ldapinfo in the avl tree */
620 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
621 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
622 (caddr_t)&li, ldap_chain_uri_cmp );
623 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
626 op->o_bd->be_private = (void *)lip;
629 /* if none is found, create a temporary... */
630 rc = ldap_chain_db_init_one( op->o_bd );
634 lip = (ldapinfo_t *)op->o_bd->be_private;
635 lip->li_uri = li.li_uri;
636 lip->li_bvuri = bvuri;
637 rc = ldap_chain_db_open_one( op->o_bd );
640 lip->li_bvuri = NULL;
641 (void)ldap_chain_db_destroy_one( op->o_bd );
645 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
646 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
647 if ( avl_insert( &lc->lc_lai.lai_tree,
648 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
650 /* someone just inserted another;
651 * don't bother, use this and then
655 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
662 lb->lb_op_f = lback->bi_op_search;
663 lb->lb_depth = depth + 1;
665 /* FIXME: should we also copy filter and scope?
666 * according to RFC3296, no */
667 rc = lback->bi_op_search( op, rs );
668 if ( first_rc == -1 ) {
673 ldap_memfree( li.li_uri );
676 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
677 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
681 lip->li_bvuri = NULL;
682 (void)ldap_chain_db_close_one( op->o_bd );
683 (void)ldap_chain_db_destroy_one( op->o_bd );
686 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
693 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
694 (void)chaining_control_remove( op, &ctrls );
695 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
698 op->o_req_ndn = ondn;
699 op->o_callback->sc_response = save_response;
700 rs->sr_type = REP_SEARCHREF;
703 if ( rc != LDAP_SUCCESS ) {
704 /* couldn't chase any of the referrals */
705 if ( first_rc != -1 ) {
709 rc = SLAP_CB_CONTINUE;
717 ldap_chain_response( Operation *op, SlapReply *rs )
719 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
720 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
721 BackendDB db, *bd = op->o_bd;
722 ldap_chain_cb_t lb = { 0 };
723 slap_callback *sc = op->o_callback,
728 struct berval ndn = op->o_ndn;
730 int sr_err = rs->sr_err;
731 slap_reply_t sr_type = rs->sr_type;
732 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
733 slap_mask_t chain_mask = 0;
734 ber_len_t chain_shift = 0;
735 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
737 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
738 return SLAP_CB_CONTINUE;
741 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
742 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
743 switch ( get_resolveBehavior( op ) ) {
744 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
745 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
746 return SLAP_CB_CONTINUE;
749 chain_mask = SLAP_CH_RESOLVE_MASK;
750 chain_shift = SLAP_CH_RESOLVE_SHIFT;
754 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
755 switch ( get_continuationBehavior( op ) ) {
756 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
757 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
758 return SLAP_CB_CONTINUE;
761 chain_mask = SLAP_CH_CONTINUATION_MASK;
762 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
766 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
769 * TODO: add checks on who/when chain operations; e.g.:
770 * a) what identities are authorized
771 * b) what request DN (e.g. only chain requests rooted at <DN>)
772 * c) what referral URIs
773 * d) what protocol scheme (e.g. only ldaps://)
778 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
781 matched = rs->sr_matched;
782 rs->sr_matched = NULL;
786 /* we need this to know if back-ldap returned any result */
788 sc2.sc_private = &lb;
789 sc2.sc_response = ldap_chain_cb_response;
790 op->o_callback = &sc2;
792 /* Chaining can be performed by a privileged user on behalf
793 * of normal users, using the ProxyAuthz control, by exploiting
794 * the identity assertion feature of back-ldap; see idassert-*
795 * directives in slapd-ldap(5).
797 * FIXME: the idassert-authcDN is one, will it be fine regardless
798 * of the URI we obtain from the referral?
801 switch ( op->o_tag ) {
802 case LDAP_REQ_BIND: {
803 struct berval rndn = op->o_req_ndn;
804 Connection *conn = op->o_conn;
806 /* FIXME: can we really get a referral for binds? */
807 op->o_req_ndn = slap_empty_bv;
809 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
810 op->o_req_ndn = rndn;
816 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
819 case LDAP_REQ_DELETE:
820 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
823 case LDAP_REQ_MODRDN:
824 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
827 case LDAP_REQ_MODIFY:
828 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
831 case LDAP_REQ_COMPARE:
832 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
833 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
838 case LDAP_REQ_SEARCH:
839 if ( rs->sr_type == REP_SEARCHREF ) {
840 rc = ldap_chain_search( op, rs, ref, 0 );
843 /* we might get here before any database actually
844 * performed a search; in those cases, we need
845 * to check limits, to make sure safe defaults
847 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
848 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
851 rc = SLAP_CB_CONTINUE;
856 case LDAP_REQ_EXTENDED:
857 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
858 /* FIXME: ldap_back_extended() by design
859 * doesn't send result; frontend is expected
861 /* FIXME: what about chaining? */
862 if ( rc != SLAPD_ABANDON ) {
863 send_ldap_extended( op, rs );
866 lb.lb_status = LDAP_CH_RES;
870 rc = SLAP_CB_CONTINUE;
880 /* slapd-ldap sent response */
881 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
882 /* FIXME: should we send response? */
883 Debug( LDAP_DEBUG_ANY,
884 "%s: ldap_chain_response: "
885 "overlay should have sent result.\n",
886 op->o_log_prefix, 0, 0 );
891 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
892 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
896 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
897 case LDAP_CHAINING_REQUIRED:
899 op->o_callback = NULL;
900 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
901 "operation cannot be completed without chaining" );
905 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
906 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
908 rs->sr_type = sr_type;
911 rc = SLAP_CB_CONTINUE;
913 rs->sr_type = sr_type;
914 rs->sr_matched = matched;
917 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
920 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
923 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
924 op->o_callback = NULL;
925 rc = rs->sr_err = slap_map_api2result( rs );
926 send_ldap_result( op, rs );
931 rs->sr_type = sr_type;
932 rs->sr_matched = matched;
941 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
943 ldap_chain_parse_ctrl(
949 str2chain( const char *s )
951 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
952 return LDAP_CHAINING_PREFERRED;
954 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
955 return LDAP_CHAINING_REQUIRED;
957 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
958 return LDAP_REFERRALS_PREFERRED;
960 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
961 return LDAP_REFERRALS_REQUIRED;
966 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
981 static ConfigDriver chain_cf_gen;
982 static ConfigCfAdd chain_cfadd;
983 static ConfigLDAPadd chain_ldadd;
985 static ConfigTable chaincfg[] = {
986 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
987 { "chain-chaining", "args",
988 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
989 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
990 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
991 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
992 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
993 { "chain-cache-uri", "TRUE/FALSE",
994 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
995 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
996 "DESC 'Enables caching of URIs not present in configuration' "
997 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
998 { "chain-max-depth", "args",
999 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1000 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1001 "DESC 'max referral depth' "
1002 "SYNTAX OMsInteger "
1003 "EQUALITY integerMatch "
1004 "SINGLE-VALUE )", NULL, NULL },
1005 { "chain-return-error", "TRUE/FALSE",
1006 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1007 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1008 "DESC 'Errors are returned instead of the original referral' "
1009 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1010 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1013 static ConfigOCs chainocs[] = {
1014 { "( OLcfgOvOc:3.1 "
1015 "NAME 'olcChainConfig' "
1016 "DESC 'Chain configuration' "
1017 "SUP olcOverlayConfig "
1019 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1020 "olcChainingBehavior $ "
1021 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1022 "olcChainCacheURI $ "
1023 "olcChainMaxReferralDepth $ "
1024 "olcChainReturnError "
1026 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1027 { "( OLcfgOvOc:3.2 "
1028 "NAME 'olcChainDatabase' "
1029 "DESC 'Chain remote server configuration' "
1031 Cft_Misc, chaincfg, chain_ldadd },
1036 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1043 AttributeDescription *ad = NULL;
1049 if ( p->ce_type != Cft_Overlay
1051 || p->ce_bi->bi_cf_ocs != chainocs )
1053 return LDAP_CONSTRAINT_VIOLATION;
1056 on = (slap_overinst *)p->ce_bi;
1057 lc = (ldap_chain_t *)on->on_bi.bi_private;
1059 assert( ca->be == NULL );
1060 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1062 ca->be->bd_info = (BackendInfo *)on;
1064 rc = slap_str2ad( "olcDbURI", &ad, &text );
1065 assert( rc == LDAP_SUCCESS );
1067 at = attr_find( e->e_attrs, ad );
1068 if ( lc->lc_common_li == NULL && at != NULL ) {
1069 /* FIXME: we should generate an empty default entry
1070 * if none is supplied */
1071 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1072 "first underlying database \"%s\" "
1073 "cannot contain attribute \"%s\".\n",
1074 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1075 rc = LDAP_CONSTRAINT_VIOLATION;
1078 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1079 /* FIXME: we should generate an empty default entry
1080 * if none is supplied */
1081 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1082 "subsequent underlying database \"%s\" "
1083 "must contain attribute \"%s\".\n",
1084 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1085 rc = LDAP_CONSTRAINT_VIOLATION;
1089 if ( lc->lc_common_li == NULL ) {
1090 rc = ldap_chain_db_init_common( ca->be );
1093 rc = ldap_chain_db_init_one( ca->be );
1097 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1098 "unable to init %sunderlying database \"%s\".\n",
1099 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1100 return LDAP_CONSTRAINT_VIOLATION;
1103 li = ca->be->be_private;
1105 if ( lc->lc_common_li == NULL ) {
1106 lc->lc_common_li = li;
1109 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1110 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1111 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1112 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1114 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1115 "database \"%s\" insert failed.\n",
1116 e->e_name.bv_val, 0, 0 );
1117 rc = LDAP_CONSTRAINT_VIOLATION;
1123 if ( rc != LDAP_SUCCESS ) {
1124 (void)ldap_chain_db_destroy_one( ca->be );
1132 typedef struct ldap_chain_cfadd_apply_t {
1138 } ldap_chain_cfadd_apply_t;
1141 ldap_chain_cfadd_apply( void *datum, void *arg )
1143 ldapinfo_t *li = (ldapinfo_t *)datum;
1144 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1148 /* FIXME: should not hardcode "olcDatabase" here */
1149 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1150 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1151 bv.bv_val = lca->ca->msg;
1153 lca->ca->be->be_private = (void *)li;
1154 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1155 &bv, lback->bi_cf_ocs, &chainocs[1] );
1163 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1165 CfEntryInfo *pe = p->e_private;
1166 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1167 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1168 void *priv = (void *)ca->be->be_private;
1170 if ( lback->bi_cf_ocs ) {
1171 ldap_chain_cfadd_apply_t lca = { 0 };
1179 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1181 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1182 &lca, 1, AVL_INORDER );
1184 ca->be->be_private = priv;
1190 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1191 static slap_verbmasks chaining_mode[] = {
1192 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1193 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1194 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1195 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1198 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1201 chain_cf_gen( ConfigArgs *c )
1203 slap_overinst *on = (slap_overinst *)c->bi;
1204 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1208 if ( c->op == SLAP_CONFIG_EMIT ) {
1210 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1212 struct berval resolve = BER_BVNULL,
1213 continuation = BER_BVNULL;
1215 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1219 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1220 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1222 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1224 + STRLENOF( "continuation=" ) + continuation.bv_len;
1225 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1226 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1227 "resolve=%s continuation=%s",
1228 resolve.bv_val, continuation.bv_val );
1230 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1231 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1232 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1233 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1234 " critical", STRLENOF( " critical" ) + 1 );
1235 c->value_bv.bv_len += STRLENOF( " critical" );
1240 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1243 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1247 c->value_int = lc->lc_max_depth;
1251 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1260 } else if ( c->op == LDAP_MOD_DELETE ) {
1266 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1274 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1285 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1286 char **argv = c->argv;
1288 BerElementBuffer berbuf;
1289 BerElement *ber = (BerElement *)&berbuf;
1293 Operation op = { 0 };
1294 SlapReply rs = { 0 };
1296 lc->lc_chaining_ctrlflag = 0;
1298 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1299 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1300 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1301 if ( resolve == -1 ) {
1302 Debug( LDAP_DEBUG_ANY, "%s: "
1303 "illegal <resolve> value %s "
1304 "in \"chain-chaining>\".\n",
1305 c->log, argv[ 0 ], 0 );
1309 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1310 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1311 if ( continuation == -1 ) {
1312 Debug( LDAP_DEBUG_ANY, "%s: "
1313 "illegal <continuation> value %s "
1314 "in \"chain-chaining\".\n",
1315 c->log, argv[ 0 ], 0 );
1319 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1323 Debug( LDAP_DEBUG_ANY, "%s: "
1324 "unknown option in \"chain-chaining\".\n",
1330 if ( resolve != -1 || continuation != -1 ) {
1333 if ( resolve == -1 ) {
1335 resolve = SLAP_CHAINING_DEFAULT;
1338 ber_init2( ber, NULL, LBER_USE_DER );
1340 err = ber_printf( ber, "{e" /* } */, resolve );
1343 Debug( LDAP_DEBUG_ANY, "%s: "
1344 "chaining behavior control encoding error!\n",
1349 if ( continuation > -1 ) {
1350 err = ber_printf( ber, "e", continuation );
1353 Debug( LDAP_DEBUG_ANY, "%s: "
1354 "chaining behavior control encoding error!\n",
1360 err = ber_printf( ber, /* { */ "N}" );
1363 Debug( LDAP_DEBUG_ANY, "%s: "
1364 "chaining behavior control encoding error!\n",
1369 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1370 exit( EXIT_FAILURE );
1374 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1377 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1378 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1380 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1382 Debug( LDAP_DEBUG_ANY, "%s: "
1383 "unable to parse chaining control%s%s.\n",
1384 c->log, rs.sr_text ? ": " : "",
1385 rs.sr_text ? rs.sr_text : "" );
1389 lc->lc_chaining_ctrlflag = op.o_chaining;
1391 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1394 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1395 Debug( LDAP_DEBUG_ANY, "%s: "
1396 "\"chaining\" control unsupported (ignored).\n",
1398 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1402 if ( c->value_int ) {
1403 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1405 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1410 if ( c->value_int < 0 ) {
1411 snprintf( c->msg, sizeof( c->msg ),
1412 "<%s> invalid max referral depth %d",
1413 c->argv[0], c->value_int );
1414 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1415 c->log, c->msg, 0 );
1419 lc->lc_max_depth = c->value_int;
1422 if ( c->value_int ) {
1423 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1425 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1440 slap_overinst *on = (slap_overinst *)be->bd_info;
1441 ldap_chain_t *lc = NULL;
1443 if ( lback == NULL ) {
1444 static BackendInfo lback2;
1446 lback = backend_info( "ldap" );
1448 if ( lback == NULL ) {
1453 lback2.bi_type = ldapchain.on_bi.bi_type;
1457 lc = ch_malloc( sizeof( ldap_chain_t ) );
1461 memset( lc, 0, sizeof( ldap_chain_t ) );
1462 lc->lc_max_depth = 1;
1463 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1465 on->on_bi.bi_private = (void *)lc;
1471 ldap_chain_db_config(
1478 slap_overinst *on = (slap_overinst *)be->bd_info;
1479 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1481 int rc = SLAP_CONF_UNKNOWN;
1483 if ( lc->lc_common_li == NULL ) {
1484 void *be_private = be->be_private;
1485 ldap_chain_db_init_common( be );
1486 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1487 be->be_private = be_private;
1490 /* Something for the chain database? */
1491 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1492 char *save_argv0 = argv[ 0 ];
1493 BackendInfo *bd_info = be->bd_info;
1494 void *be_private = be->be_private;
1495 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1496 static char *allowed_argv[] = {
1497 /* special: put URI here, so in the meanwhile
1498 * it detects whether a new URI is being provided */
1504 /* FIXME: maybe rebind-as-user should be allowed
1505 * only within known URIs... */
1512 int which_argv = -1;
1514 argv[ 0 ] += STRLENOF( "chain-" );
1516 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1517 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1522 if ( allowed_argv[ which_argv ] == NULL ) {
1525 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1526 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1527 "\"%s\" only allowed within a URI directive.\n.",
1528 fname, lineno, argv[ 0 ] );
1533 if ( which_argv == 0 ) {
1534 rc = ldap_chain_db_init_one( be );
1536 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1537 "underlying slapd-ldap initialization failed.\n.",
1541 lc->lc_cfg_li = be->be_private;
1544 /* TODO: add checks on what other slapd-ldap(5) args
1545 * should be put in the template; this is not quite
1546 * harmful, because attributes that shouldn't don't
1547 * get actually used, but the user should at least
1551 be->bd_info = lback;
1552 be->be_private = (void *)lc->lc_cfg_li;
1553 be->be_cf_ocs = lback->bi_cf_ocs;
1555 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1557 argv[ 0 ] = save_argv0;
1558 be->be_cf_ocs = be_cf_ocs;
1559 be->be_private = be_private;
1560 be->bd_info = bd_info;
1562 if ( which_argv == 0 ) {
1568 db.be_private = (void *)lc->lc_cfg_li;
1569 ldap_chain_db_destroy_one( &db );
1570 lc->lc_cfg_li = NULL;
1573 if ( lc->lc_cfg_li->li_bvuri == NULL
1574 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1575 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1577 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1578 "no URI list allowed in slapo-chain.\n",
1581 goto private_destroy;
1584 if ( avl_insert( &lc->lc_lai.lai_tree,
1585 (caddr_t)lc->lc_cfg_li,
1586 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1588 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1589 "duplicate URI in slapo-chain.\n",
1592 goto private_destroy;
1609 typedef struct ldap_chain_db_apply_t {
1612 } ldap_chain_db_apply_t;
1615 ldap_chain_db_apply( void *datum, void *arg )
1617 ldapinfo_t *li = (ldapinfo_t *)datum;
1618 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1620 lca->be->be_private = (void *)li;
1622 return lca->func( lca->be );
1631 slap_overinst *on = (slap_overinst *)be->bd_info;
1632 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1637 BI_db_func *func = (&lback->bi_db_open)[ which ];
1639 if ( func != NULL && lc->lc_common_li != NULL ) {
1643 db.be_private = lc->lc_common_li;
1651 if ( lc->lc_lai.lai_tree != NULL ) {
1652 ldap_chain_db_apply_t lca;
1657 rc = avl_apply( lc->lc_lai.lai_tree,
1658 ldap_chain_db_apply, (void *)&lca,
1659 1, AVL_INORDER ) != AVL_NOMORE;
1671 slap_overinst *on = (slap_overinst *) be->bd_info;
1672 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1673 slap_mask_t monitoring;
1676 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1677 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1681 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1683 if ( lc->lc_common_li == NULL ) {
1684 void *be_private = be->be_private;
1685 ldap_chain_db_init_common( be );
1686 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1687 be->be_private = be_private;
1690 /* filter out and restore monitoring */
1691 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1692 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1693 rc = ldap_chain_db_func( be, db_open );
1694 SLAP_DBFLAGS( be ) |= monitoring;
1700 ldap_chain_db_close(
1703 return ldap_chain_db_func( be, db_close );
1707 ldap_chain_db_destroy(
1710 slap_overinst *on = (slap_overinst *) be->bd_info;
1711 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1715 rc = ldap_chain_db_func( be, db_destroy );
1718 avl_free( lc->lc_lai.lai_tree, NULL );
1719 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1727 * inits one instance of the slapd-ldap backend, and stores
1728 * the private info in be_private of the arg
1731 ldap_chain_db_init_common(
1734 BackendInfo *bi = be->bd_info;
1738 be->bd_info = lback;
1739 be->be_private = NULL;
1740 rc = lback->bi_db_init( be );
1744 li = (ldapinfo_t *)be->be_private;
1745 li->li_urllist_f = NULL;
1746 li->li_urllist_p = NULL;
1754 * inits one instance of the slapd-ldap backend, stores
1755 * the private info in be_private of the arg and fills
1756 * selected fields with data from the template.
1758 * NOTE: add checks about the other fields of the template,
1759 * which are ignored and SHOULD NOT be configured by the user.
1762 ldap_chain_db_init_one(
1765 slap_overinst *on = (slap_overinst *)be->bd_info;
1766 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1768 BackendInfo *bi = be->bd_info;
1773 be->bd_info = lback;
1774 be->be_private = NULL;
1775 t = lback->bi_db_init( be );
1779 li = (ldapinfo_t *)be->be_private;
1780 li->li_urllist_f = NULL;
1781 li->li_urllist_p = NULL;
1783 /* copy common data */
1784 li->li_nretries = lc->lc_common_li->li_nretries;
1785 li->li_flags = lc->lc_common_li->li_flags;
1786 li->li_version = lc->lc_common_li->li_version;
1787 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1788 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1796 ldap_chain_db_open_one(
1799 if ( SLAP_DBMONITORING( be ) ) {
1800 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1802 if ( li->li_uri == NULL ) {
1803 ber_str2bv( "cn=Common Connections", 0, 1,
1804 &li->li_monitor_info.lmi_rdn );
1809 li->li_monitor_info.lmi_rdn.bv_len
1810 = STRLENOF( "cn=" ) + strlen( li->li_uri );
1811 ptr = li->li_monitor_info.lmi_rdn.bv_val
1812 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
1813 ptr = lutil_strcopy( ptr, "cn=" );
1814 ptr = lutil_strcopy( ptr, li->li_uri );
1819 return lback->bi_db_open( be );
1822 typedef struct ldap_chain_conn_apply_t {
1825 } ldap_chain_conn_apply_t;
1828 ldap_chain_conn_apply( void *datum, void *arg )
1830 ldapinfo_t *li = (ldapinfo_t *)datum;
1831 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1833 lca->be->be_private = (void *)li;
1835 return lback->bi_connection_destroy( lca->be, lca->conn );
1839 ldap_chain_connection_destroy(
1844 slap_overinst *on = (slap_overinst *) be->bd_info;
1845 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1846 void *private = be->be_private;
1847 ldap_chain_conn_apply_t lca;
1850 be->be_private = NULL;
1853 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1854 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1855 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1856 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1857 be->be_private = private;
1862 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1864 ldap_chain_parse_ctrl(
1874 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1875 rs->sr_text = "Chaining behavior control specified multiple times";
1876 return LDAP_PROTOCOL_ERROR;
1879 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1880 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1881 return LDAP_PROTOCOL_ERROR;
1884 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1885 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1890 /* Parse the control value
1891 * ChainingBehavior ::= SEQUENCE {
1892 * resolveBehavior Behavior OPTIONAL,
1893 * continuationBehavior Behavior OPTIONAL }
1895 * Behavior :: = ENUMERATED {
1896 * chainingPreferred (0),
1897 * chainingRequired (1),
1898 * referralsPreferred (2),
1899 * referralsRequired (3) }
1902 ber = ber_init( &ctrl->ldctl_value );
1904 rs->sr_text = "internal error";
1908 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1909 /* FIXME: since the whole SEQUENCE is optional,
1910 * should we accept no enumerations at all? */
1911 if ( tag != LBER_ENUMERATED ) {
1912 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1913 return LDAP_PROTOCOL_ERROR;
1916 switch ( behavior ) {
1917 case LDAP_CHAINING_PREFERRED:
1918 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1921 case LDAP_CHAINING_REQUIRED:
1922 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1925 case LDAP_REFERRALS_PREFERRED:
1926 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1929 case LDAP_REFERRALS_REQUIRED:
1930 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1934 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1935 return LDAP_PROTOCOL_ERROR;
1938 tag = ber_peek_tag( ber, &len );
1939 if ( tag == LBER_ENUMERATED ) {
1940 tag = ber_scanf( ber, "e", &behavior );
1941 if ( tag == LBER_ERROR ) {
1942 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1943 return LDAP_PROTOCOL_ERROR;
1947 if ( tag == LBER_DEFAULT ) {
1948 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1951 switch ( behavior ) {
1952 case LDAP_CHAINING_PREFERRED:
1953 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1956 case LDAP_CHAINING_REQUIRED:
1957 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1960 case LDAP_REFERRALS_PREFERRED:
1961 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1964 case LDAP_REFERRALS_REQUIRED:
1965 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1969 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1970 return LDAP_PROTOCOL_ERROR;
1974 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1975 rs->sr_text = "Chaining behavior control: decoding error";
1976 return LDAP_PROTOCOL_ERROR;
1979 (void) ber_free( ber, 1 );
1982 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1983 ? SLAP_CONTROL_CRITICAL
1984 : SLAP_CONTROL_NONCRITICAL );
1986 return LDAP_SUCCESS;
1988 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1991 chain_initialize( void )
1995 /* Make sure we don't exceed the bits reserved for userland */
1996 config_check_userland( CH_LAST );
1998 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1999 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2000 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2001 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2002 if ( rc != LDAP_SUCCESS ) {
2003 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2004 "unable to register chaining behavior control: %d.\n",
2008 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2010 ldapchain.on_bi.bi_type = "chain";
2011 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2012 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2013 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2014 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2015 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2017 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2019 ldapchain.on_response = ldap_chain_response;
2021 ldapchain.on_bi.bi_cf_ocs = chainocs;
2023 rc = config_register_schema( chaincfg, chainocs );
2028 return overlay_register( &ldapchain );