1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2008 The OpenLDAP Foundation.
6 * Portions Copyright 2003 Howard Chu.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by the Howard Chu for inclusion
19 * in OpenLDAP Software.
20 * This work was subsequently modified by Pierangelo Masarati.
27 #include <ac/string.h>
28 #include <ac/socket.h>
32 #include "back-ldap.h"
35 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
36 #define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED
37 #define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT
38 #define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT)
39 #define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
40 #define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
41 #define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
42 #define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
43 #define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
44 #define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2)
45 #define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT)
46 #define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
47 #define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
48 #define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
49 #define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
50 #define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
52 #define o_chaining o_ctrlflag[sc_chainingBehavior]
53 #define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK)
54 #define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
55 #define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
56 #define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
58 static int sc_chainingBehavior;
59 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
65 } ldap_chain_status_t;
66 static BackendInfo *lback;
68 typedef struct ldap_chain_t {
70 * A "template" ldapinfo_t gets all common configuration items;
71 * then, for each configured URI, an entry is created in the tree;
72 * all the specific configuration items get in the current URI
75 * Then, for each referral, extract the URI and lookup the
76 * related structure. If configured to do so, allow URIs
77 * not found in the structure to create a temporary one
78 * that chains anonymously; maybe it can also be added to
79 * the tree? Should be all configurable.
82 /* "common" configuration info (anything occurring before an "uri") */
83 ldapinfo_t *lc_common_li;
85 /* current configuration info */
86 ldapinfo_t *lc_cfg_li;
88 /* tree of configured[/generated?] "uri" info */
89 ldap_avl_info_t lc_lai;
91 /* max depth in nested referrals chaining */
95 #define LDAP_CHAIN_F_NONE (0x00U)
96 #define LDAP_CHAIN_F_CHAINING (0x01U)
97 #define LDAP_CHAIN_F_CACHE_URI (0x02U)
98 #define LDAP_CHAIN_F_RETURN_ERR (0x04U)
100 #define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
101 #define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
102 #define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
103 #define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
105 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
106 LDAPControl lc_chaining_ctrl;
107 char lc_chaining_ctrlflag;
108 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
111 static int ldap_chain_db_init_common( BackendDB *be );
112 static int ldap_chain_db_init_one( BackendDB *be );
113 static int ldap_chain_db_open_one( BackendDB *be );
114 #define ldap_chain_db_close_one(be) (0)
115 #define ldap_chain_db_destroy_one(be) (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++ ) {
417 SlapReply rs2 = { 0 };
418 LDAPURLDesc *srv = NULL;
419 struct berval save_req_dn = op->o_req_dn,
420 save_req_ndn = op->o_req_ndn,
426 /* We're setting the URI of the first referral;
427 * what if there are more?
433 If the client wishes to progress the operation, it MUST follow the
434 referral by contacting one of the supported services. If multiple
435 URIs are present, the client assumes that any supported URI may be
436 used to progress the operation.
438 * so we actually need to follow exactly one,
439 * and we can assume any is fine.
442 /* parse reference and use
443 * proto://[host][:port]/ only */
444 rc = ldap_url_parse_ext( ref->bv_val, &srv );
445 if ( rc != LDAP_URL_SUCCESS ) {
453 srv->lud_scope = LDAP_SCOPE_DEFAULT;
454 if ( srv->lud_dn != NULL ) {
455 ber_str2bv( srv->lud_dn, 0, 0, &dn );
456 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
457 if ( rc == LDAP_SUCCESS ) {
458 /* remove DN essentially because later on
459 * ldap_initialize() will parse the URL
460 * as a comma-separated URL list */
468 li.li_uri = ldap_url_desc2str( srv );
469 srv->lud_dn = dn.bv_val;
470 ldap_free_urldesc( srv );
472 if ( rc != LDAP_SUCCESS ) {
478 if ( li.li_uri == NULL ) {
481 goto further_cleanup;
487 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
489 /* Searches for a ldapinfo in the avl tree */
490 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
491 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
492 (caddr_t)&li, ldap_chain_uri_cmp );
493 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
496 op->o_bd->be_private = (void *)lip;
499 rc = ldap_chain_db_init_one( op->o_bd );
503 lip = (ldapinfo_t *)op->o_bd->be_private;
504 lip->li_uri = li.li_uri;
505 lip->li_bvuri = bvuri;
506 rc = ldap_chain_db_open_one( op->o_bd );
509 lip->li_bvuri = NULL;
510 (void)ldap_chain_db_destroy_one( op->o_bd );
514 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
515 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
516 if ( avl_insert( &lc->lc_lai.lai_tree,
517 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
519 /* someone just inserted another;
520 * don't bother, use this and then
524 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
532 lb->lb_depth = depth + 1;
534 rc = op_f( op, &rs2 );
536 /* note the first error */
537 if ( first_rc == -1 ) {
542 ldap_memfree( li.li_uri );
547 lip->li_bvuri = NULL;
548 (void)ldap_chain_db_close_one( op->o_bd );
549 (void)ldap_chain_db_destroy_one( op->o_bd );
553 if ( !BER_BVISNULL( &pdn ) ) {
554 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
556 op->o_req_dn = save_req_dn;
558 if ( !BER_BVISNULL( &ndn ) ) {
559 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
561 op->o_req_ndn = save_req_ndn;
563 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
571 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
572 (void)chaining_control_remove( op, &ctrls );
573 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
575 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
590 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
591 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
592 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
593 ldapinfo_t li = { 0 }, *lip = NULL;
594 struct berval bvuri[ 2 ] = { { 0 } };
596 struct berval odn = op->o_req_dn,
597 ondn = op->o_req_ndn;
598 slap_response *save_response = op->o_callback->sc_response;
603 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
604 LDAPControl **ctrls = NULL;
606 (void)chaining_control_add( lc, op, &ctrls );
607 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
609 rs->sr_type = REP_SEARCH;
611 op->o_callback->sc_response = ldap_chain_cb_search_response;
613 /* if we parse the URI then by no means
614 * we can cache stuff or reuse connections,
615 * because in back-ldap there's no caching
616 * based on the URI value, which is supposed
617 * to be set once for all (correct?) */
619 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
620 SlapReply rs2 = { 0 };
622 struct berval save_req_dn = op->o_req_dn,
623 save_req_ndn = op->o_req_ndn,
629 /* parse reference and use
630 * proto://[host][:port]/ only */
631 rc = ldap_url_parse_ext( ref[0].bv_val, &srv );
632 if ( rc != LDAP_URL_SUCCESS ) {
634 rs->sr_err = LDAP_OTHER;
639 rc = LDAP_INVALID_SYNTAX;
640 if ( srv->lud_dn != NULL ) {
641 ber_str2bv( srv->lud_dn, 0, 0, &dn );
642 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
643 if ( rc == LDAP_SUCCESS ) {
644 /* remove DN essentially because later on
645 * ldap_initialize() will parse the URL
646 * as a comma-separated URL list */
648 srv->lud_scope = LDAP_SCOPE_DEFAULT;
649 li.li_uri = ldap_url_desc2str( srv );
650 srv->lud_dn = dn.bv_val;
653 ldap_free_urldesc( srv );
655 if ( rc != LDAP_SUCCESS ) {
661 if ( li.li_uri == NULL ) {
664 goto further_cleanup;
670 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
672 /* Searches for a ldapinfo in the avl tree */
673 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
674 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
675 (caddr_t)&li, ldap_chain_uri_cmp );
676 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
679 op->o_bd->be_private = (void *)lip;
682 /* if none is found, create a temporary... */
683 rc = ldap_chain_db_init_one( op->o_bd );
687 lip = (ldapinfo_t *)op->o_bd->be_private;
688 lip->li_uri = li.li_uri;
689 lip->li_bvuri = bvuri;
690 rc = ldap_chain_db_open_one( op->o_bd );
693 lip->li_bvuri = NULL;
694 (void)ldap_chain_db_destroy_one( op->o_bd );
698 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
699 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
700 if ( avl_insert( &lc->lc_lai.lai_tree,
701 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
703 /* someone just inserted another;
704 * don't bother, use this and then
708 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
715 lb->lb_op_f = lback->bi_op_search;
716 lb->lb_depth = depth + 1;
718 /* FIXME: should we also copy filter and scope?
719 * according to RFC3296, no */
720 rc = lback->bi_op_search( op, &rs2 );
721 if ( first_rc == -1 ) {
726 ldap_memfree( li.li_uri );
731 lip->li_bvuri = NULL;
732 (void)ldap_chain_db_close_one( op->o_bd );
733 (void)ldap_chain_db_destroy_one( op->o_bd );
737 if ( !BER_BVISNULL( &pdn ) ) {
738 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
740 op->o_req_dn = save_req_dn;
742 if ( !BER_BVISNULL( &ndn ) ) {
743 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
745 op->o_req_ndn = save_req_ndn;
747 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
755 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
756 (void)chaining_control_remove( op, &ctrls );
757 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
760 op->o_req_ndn = ondn;
761 op->o_callback->sc_response = save_response;
762 rs->sr_type = REP_SEARCHREF;
765 if ( rc != LDAP_SUCCESS ) {
766 /* couldn't chase any of the referrals */
767 if ( first_rc != -1 ) {
771 rc = SLAP_CB_CONTINUE;
779 ldap_chain_response( Operation *op, SlapReply *rs )
781 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
782 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
783 BackendDB db, *bd = op->o_bd;
784 ldap_chain_cb_t lb = { 0 };
785 slap_callback *sc = op->o_callback,
788 const char *text = NULL;
791 struct berval ndn = op->o_ndn;
793 int sr_err = rs->sr_err;
794 slap_reply_t sr_type = rs->sr_type;
795 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
796 slap_mask_t chain_mask = 0;
797 ber_len_t chain_shift = 0;
798 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
800 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
801 return SLAP_CB_CONTINUE;
804 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
805 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
806 switch ( get_resolveBehavior( op ) ) {
807 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
808 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
809 return SLAP_CB_CONTINUE;
812 chain_mask = SLAP_CH_RESOLVE_MASK;
813 chain_shift = SLAP_CH_RESOLVE_SHIFT;
817 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
818 switch ( get_continuationBehavior( op ) ) {
819 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
820 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
821 return SLAP_CB_CONTINUE;
824 chain_mask = SLAP_CH_CONTINUATION_MASK;
825 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
829 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
832 * TODO: add checks on who/when chain operations; e.g.:
833 * a) what identities are authorized
834 * b) what request DN (e.g. only chain requests rooted at <DN>)
835 * c) what referral URIs
836 * d) what protocol scheme (e.g. only ldaps://)
845 matched = rs->sr_matched;
846 rs->sr_matched = NULL;
850 /* we need this to know if back-ldap returned any result */
852 sc2.sc_private = &lb;
853 sc2.sc_response = ldap_chain_cb_response;
854 op->o_callback = &sc2;
856 /* Chaining can be performed by a privileged user on behalf
857 * of normal users, using the ProxyAuthz control, by exploiting
858 * the identity assertion feature of back-ldap; see idassert-*
859 * directives in slapd-ldap(5).
861 * FIXME: the idassert-authcDN is one, will it be fine regardless
862 * of the URI we obtain from the referral?
865 switch ( op->o_tag ) {
866 case LDAP_REQ_BIND: {
867 struct berval rndn = op->o_req_ndn;
868 Connection *conn = op->o_conn;
870 /* FIXME: can we really get a referral for binds? */
871 op->o_req_ndn = slap_empty_bv;
873 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
874 op->o_req_ndn = rndn;
880 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
883 case LDAP_REQ_DELETE:
884 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
887 case LDAP_REQ_MODRDN:
888 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
891 case LDAP_REQ_MODIFY:
892 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
895 case LDAP_REQ_COMPARE:
896 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
897 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
902 case LDAP_REQ_SEARCH:
903 if ( rs->sr_type == REP_SEARCHREF ) {
904 rc = ldap_chain_search( op, rs, ref, 0 );
907 /* we might get here before any database actually
908 * performed a search; in those cases, we need
909 * to check limits, to make sure safe defaults
911 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
912 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
915 rc = SLAP_CB_CONTINUE;
920 case LDAP_REQ_EXTENDED:
921 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
922 /* FIXME: ldap_back_extended() by design
923 * doesn't send result; frontend is expected
925 /* FIXME: what about chaining? */
926 if ( rc != SLAPD_ABANDON ) {
928 send_ldap_extended( op, rs );
931 lb.lb_status = LDAP_CH_RES;
935 rc = SLAP_CB_CONTINUE;
945 /* slapd-ldap sent response */
946 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
947 /* FIXME: should we send response? */
948 Debug( LDAP_DEBUG_ANY,
949 "%s: ldap_chain_response: "
950 "overlay should have sent result.\n",
951 op->o_log_prefix, 0, 0 );
956 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
957 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
961 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
962 case LDAP_CHAINING_REQUIRED:
964 op->o_callback = NULL;
965 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
966 "operation cannot be completed without chaining" );
970 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
971 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
973 rs->sr_type = sr_type;
976 rc = SLAP_CB_CONTINUE;
978 rs->sr_type = sr_type;
980 rs->sr_matched = matched;
983 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
986 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
989 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
990 op->o_callback = NULL;
991 rc = rs->sr_err = slap_map_api2result( rs );
992 send_ldap_result( op, rs );
997 rs->sr_type = sr_type;
999 rs->sr_matched = matched;
1002 op->o_callback = sc;
1008 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1010 ldap_chain_parse_ctrl(
1013 LDAPControl *ctrl );
1016 str2chain( const char *s )
1018 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1019 return LDAP_CHAINING_PREFERRED;
1021 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1022 return LDAP_CHAINING_REQUIRED;
1024 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1025 return LDAP_REFERRALS_PREFERRED;
1027 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1028 return LDAP_REFERRALS_REQUIRED;
1033 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1048 static ConfigDriver chain_cf_gen;
1049 static ConfigCfAdd chain_cfadd;
1050 static ConfigLDAPadd chain_ldadd;
1052 static ConfigTable chaincfg[] = {
1053 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1054 { "chain-chaining", "args",
1055 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1056 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1057 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1058 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1059 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1060 { "chain-cache-uri", "TRUE/FALSE",
1061 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1062 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1063 "DESC 'Enables caching of URIs not present in configuration' "
1064 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1065 { "chain-max-depth", "args",
1066 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1067 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1068 "DESC 'max referral depth' "
1069 "SYNTAX OMsInteger "
1070 "EQUALITY integerMatch "
1071 "SINGLE-VALUE )", NULL, NULL },
1072 { "chain-return-error", "TRUE/FALSE",
1073 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1074 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1075 "DESC 'Errors are returned instead of the original referral' "
1076 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1077 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1080 static ConfigOCs chainocs[] = {
1081 { "( OLcfgOvOc:3.1 "
1082 "NAME 'olcChainConfig' "
1083 "DESC 'Chain configuration' "
1084 "SUP olcOverlayConfig "
1086 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1087 "olcChainingBehavior $ "
1088 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1089 "olcChainCacheURI $ "
1090 "olcChainMaxReferralDepth $ "
1091 "olcChainReturnError "
1093 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1094 { "( OLcfgOvOc:3.2 "
1095 "NAME 'olcChainDatabase' "
1096 "DESC 'Chain remote server configuration' "
1098 Cft_Misc, chaincfg, chain_ldadd },
1103 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1110 AttributeDescription *ad = NULL;
1116 if ( p->ce_type != Cft_Overlay
1118 || p->ce_bi->bi_cf_ocs != chainocs )
1120 return LDAP_CONSTRAINT_VIOLATION;
1123 on = (slap_overinst *)p->ce_bi;
1124 lc = (ldap_chain_t *)on->on_bi.bi_private;
1126 assert( ca->be == NULL );
1127 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1129 ca->be->bd_info = (BackendInfo *)on;
1131 rc = slap_str2ad( "olcDbURI", &ad, &text );
1132 assert( rc == LDAP_SUCCESS );
1134 at = attr_find( e->e_attrs, ad );
1135 if ( lc->lc_common_li == NULL && at != NULL ) {
1136 /* FIXME: we should generate an empty default entry
1137 * if none is supplied */
1138 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1139 "first underlying database \"%s\" "
1140 "cannot contain attribute \"%s\".\n",
1141 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1142 rc = LDAP_CONSTRAINT_VIOLATION;
1145 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1146 /* FIXME: we should generate an empty default entry
1147 * if none is supplied */
1148 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1149 "subsequent underlying database \"%s\" "
1150 "must contain attribute \"%s\".\n",
1151 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1152 rc = LDAP_CONSTRAINT_VIOLATION;
1156 if ( lc->lc_common_li == NULL ) {
1157 rc = ldap_chain_db_init_common( ca->be );
1160 rc = ldap_chain_db_init_one( ca->be );
1164 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1165 "unable to init %sunderlying database \"%s\".\n",
1166 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1167 return LDAP_CONSTRAINT_VIOLATION;
1170 li = ca->be->be_private;
1172 if ( lc->lc_common_li == NULL ) {
1173 lc->lc_common_li = li;
1176 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1177 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1178 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1179 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1181 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1182 "database \"%s\" insert failed.\n",
1183 e->e_name.bv_val, 0, 0 );
1184 rc = LDAP_CONSTRAINT_VIOLATION;
1190 if ( rc != LDAP_SUCCESS ) {
1191 (void)ldap_chain_db_destroy_one( ca->be );
1199 typedef struct ldap_chain_cfadd_apply_t {
1205 } ldap_chain_cfadd_apply_t;
1208 ldap_chain_cfadd_apply( void *datum, void *arg )
1210 ldapinfo_t *li = (ldapinfo_t *)datum;
1211 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1215 /* FIXME: should not hardcode "olcDatabase" here */
1216 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1217 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1218 bv.bv_val = lca->ca->msg;
1220 lca->ca->be->be_private = (void *)li;
1221 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1222 &bv, lback->bi_cf_ocs, &chainocs[1] );
1230 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1232 CfEntryInfo *pe = p->e_private;
1233 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1234 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1235 void *priv = (void *)ca->be->be_private;
1237 if ( lback->bi_cf_ocs ) {
1238 ldap_chain_cfadd_apply_t lca = { 0 };
1246 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1248 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1249 &lca, 1, AVL_INORDER );
1251 ca->be->be_private = priv;
1257 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1258 static slap_verbmasks chaining_mode[] = {
1259 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1260 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1261 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1262 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1265 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1268 chain_cf_gen( ConfigArgs *c )
1270 slap_overinst *on = (slap_overinst *)c->bi;
1271 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1275 if ( c->op == SLAP_CONFIG_EMIT ) {
1277 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1279 struct berval resolve = BER_BVNULL,
1280 continuation = BER_BVNULL;
1282 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1286 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1287 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1289 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1291 + STRLENOF( "continuation=" ) + continuation.bv_len;
1292 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1293 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1294 "resolve=%s continuation=%s",
1295 resolve.bv_val, continuation.bv_val );
1297 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1298 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1299 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1300 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1301 " critical", STRLENOF( " critical" ) + 1 );
1302 c->value_bv.bv_len += STRLENOF( " critical" );
1307 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1310 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1314 c->value_int = lc->lc_max_depth;
1318 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1327 } else if ( c->op == LDAP_MOD_DELETE ) {
1333 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1341 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1352 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1353 char **argv = c->argv;
1355 BerElementBuffer berbuf;
1356 BerElement *ber = (BerElement *)&berbuf;
1360 Operation op = { 0 };
1361 SlapReply rs = { 0 };
1363 lc->lc_chaining_ctrlflag = 0;
1365 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1366 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1367 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1368 if ( resolve == -1 ) {
1369 Debug( LDAP_DEBUG_ANY, "%s: "
1370 "illegal <resolve> value %s "
1371 "in \"chain-chaining>\".\n",
1372 c->log, argv[ 0 ], 0 );
1376 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1377 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1378 if ( continuation == -1 ) {
1379 Debug( LDAP_DEBUG_ANY, "%s: "
1380 "illegal <continuation> value %s "
1381 "in \"chain-chaining\".\n",
1382 c->log, argv[ 0 ], 0 );
1386 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1390 Debug( LDAP_DEBUG_ANY, "%s: "
1391 "unknown option in \"chain-chaining\".\n",
1397 if ( resolve != -1 || continuation != -1 ) {
1400 if ( resolve == -1 ) {
1402 resolve = SLAP_CHAINING_DEFAULT;
1405 ber_init2( ber, NULL, LBER_USE_DER );
1407 err = ber_printf( ber, "{e" /* } */, resolve );
1410 Debug( LDAP_DEBUG_ANY, "%s: "
1411 "chaining behavior control encoding error!\n",
1416 if ( continuation > -1 ) {
1417 err = ber_printf( ber, "e", continuation );
1420 Debug( LDAP_DEBUG_ANY, "%s: "
1421 "chaining behavior control encoding error!\n",
1427 err = ber_printf( ber, /* { */ "N}" );
1430 Debug( LDAP_DEBUG_ANY, "%s: "
1431 "chaining behavior control encoding error!\n",
1436 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1437 exit( EXIT_FAILURE );
1441 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1444 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1445 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1447 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1449 Debug( LDAP_DEBUG_ANY, "%s: "
1450 "unable to parse chaining control%s%s.\n",
1451 c->log, rs.sr_text ? ": " : "",
1452 rs.sr_text ? rs.sr_text : "" );
1456 lc->lc_chaining_ctrlflag = op.o_chaining;
1458 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1461 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1462 Debug( LDAP_DEBUG_ANY, "%s: "
1463 "\"chaining\" control unsupported (ignored).\n",
1465 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1469 if ( c->value_int ) {
1470 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1472 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1477 if ( c->value_int < 0 ) {
1478 snprintf( c->msg, sizeof( c->msg ),
1479 "<%s> invalid max referral depth %d",
1480 c->argv[0], c->value_int );
1481 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1482 c->log, c->msg, 0 );
1486 lc->lc_max_depth = c->value_int;
1489 if ( c->value_int ) {
1490 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1492 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1507 slap_overinst *on = (slap_overinst *)be->bd_info;
1508 ldap_chain_t *lc = NULL;
1510 if ( lback == NULL ) {
1511 static BackendInfo lback2;
1513 lback = backend_info( "ldap" );
1515 if ( lback == NULL ) {
1520 lback2.bi_type = ldapchain.on_bi.bi_type;
1524 lc = ch_malloc( sizeof( ldap_chain_t ) );
1528 memset( lc, 0, sizeof( ldap_chain_t ) );
1529 lc->lc_max_depth = 1;
1530 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1532 on->on_bi.bi_private = (void *)lc;
1538 ldap_chain_db_config(
1545 slap_overinst *on = (slap_overinst *)be->bd_info;
1546 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1548 int rc = SLAP_CONF_UNKNOWN;
1550 if ( lc->lc_common_li == NULL ) {
1551 void *be_private = be->be_private;
1552 ldap_chain_db_init_common( be );
1553 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1554 be->be_private = be_private;
1557 /* Something for the chain database? */
1558 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1559 char *save_argv0 = argv[ 0 ];
1560 BackendInfo *bd_info = be->bd_info;
1561 void *be_private = be->be_private;
1562 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1563 static char *allowed_argv[] = {
1564 /* special: put URI here, so in the meanwhile
1565 * it detects whether a new URI is being provided */
1571 /* FIXME: maybe rebind-as-user should be allowed
1572 * only within known URIs... */
1579 int which_argv = -1;
1581 argv[ 0 ] += STRLENOF( "chain-" );
1583 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1584 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1589 if ( allowed_argv[ which_argv ] == NULL ) {
1592 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1593 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1594 "\"%s\" only allowed within a URI directive.\n.",
1595 fname, lineno, argv[ 0 ] );
1600 if ( which_argv == 0 ) {
1601 rc = ldap_chain_db_init_one( be );
1603 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1604 "underlying slapd-ldap initialization failed.\n.",
1608 lc->lc_cfg_li = be->be_private;
1611 /* TODO: add checks on what other slapd-ldap(5) args
1612 * should be put in the template; this is not quite
1613 * harmful, because attributes that shouldn't don't
1614 * get actually used, but the user should at least
1618 be->bd_info = lback;
1619 be->be_private = (void *)lc->lc_cfg_li;
1620 be->be_cf_ocs = lback->bi_cf_ocs;
1622 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1624 argv[ 0 ] = save_argv0;
1625 be->be_cf_ocs = be_cf_ocs;
1626 be->be_private = be_private;
1627 be->bd_info = bd_info;
1629 if ( which_argv == 0 ) {
1635 db.be_private = (void *)lc->lc_cfg_li;
1636 ldap_chain_db_destroy_one( &db );
1637 lc->lc_cfg_li = NULL;
1640 if ( lc->lc_cfg_li->li_bvuri == NULL
1641 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1642 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1644 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1645 "no URI list allowed in slapo-chain.\n",
1648 goto private_destroy;
1651 if ( avl_insert( &lc->lc_lai.lai_tree,
1652 (caddr_t)lc->lc_cfg_li,
1653 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1655 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1656 "duplicate URI in slapo-chain.\n",
1659 goto private_destroy;
1676 typedef struct ldap_chain_db_apply_t {
1679 } ldap_chain_db_apply_t;
1682 ldap_chain_db_apply( void *datum, void *arg )
1684 ldapinfo_t *li = (ldapinfo_t *)datum;
1685 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1687 lca->be->be_private = (void *)li;
1689 return lca->func( lca->be );
1698 slap_overinst *on = (slap_overinst *)be->bd_info;
1699 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1704 BI_db_func *func = (&lback->bi_db_open)[ which ];
1706 if ( func != NULL && lc->lc_common_li != NULL ) {
1710 db.be_private = lc->lc_common_li;
1718 if ( lc->lc_lai.lai_tree != NULL ) {
1719 ldap_chain_db_apply_t lca;
1724 rc = avl_apply( lc->lc_lai.lai_tree,
1725 ldap_chain_db_apply, (void *)&lca,
1726 1, AVL_INORDER ) != AVL_NOMORE;
1738 slap_overinst *on = (slap_overinst *) be->bd_info;
1739 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1742 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1743 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1747 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1749 if ( lc->lc_common_li == NULL ) {
1750 void *be_private = be->be_private;
1751 ldap_chain_db_init_common( be );
1752 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1753 be->be_private = be_private;
1756 /* filter out and restore monitoring */
1757 rc = ldap_chain_db_func( be, db_open );
1763 ldap_chain_db_close(
1766 return ldap_chain_db_func( be, db_close );
1770 ldap_chain_db_destroy(
1773 slap_overinst *on = (slap_overinst *) be->bd_info;
1774 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1778 rc = ldap_chain_db_func( be, db_destroy );
1781 avl_free( lc->lc_lai.lai_tree, NULL );
1782 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1790 * inits one instance of the slapd-ldap backend, and stores
1791 * the private info in be_private of the arg
1794 ldap_chain_db_init_common(
1797 BackendInfo *bi = be->bd_info;
1801 be->bd_info = lback;
1802 be->be_private = NULL;
1803 rc = lback->bi_db_init( be );
1807 li = (ldapinfo_t *)be->be_private;
1815 * inits one instance of the slapd-ldap backend, stores
1816 * the private info in be_private of the arg and fills
1817 * selected fields with data from the template.
1819 * NOTE: add checks about the other fields of the template,
1820 * which are ignored and SHOULD NOT be configured by the user.
1823 ldap_chain_db_init_one(
1826 slap_overinst *on = (slap_overinst *)be->bd_info;
1827 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1829 BackendInfo *bi = be->bd_info;
1834 be->bd_info = lback;
1835 be->be_private = NULL;
1836 t = lback->bi_db_init( be );
1840 li = (ldapinfo_t *)be->be_private;
1842 /* copy common data */
1843 li->li_nretries = lc->lc_common_li->li_nretries;
1844 li->li_flags = lc->lc_common_li->li_flags;
1845 li->li_version = lc->lc_common_li->li_version;
1846 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1847 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1855 ldap_chain_db_open_one(
1858 return lback->bi_db_open( be );
1861 typedef struct ldap_chain_conn_apply_t {
1864 } ldap_chain_conn_apply_t;
1867 ldap_chain_conn_apply( void *datum, void *arg )
1869 ldapinfo_t *li = (ldapinfo_t *)datum;
1870 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1872 lca->be->be_private = (void *)li;
1874 return lback->bi_connection_destroy( lca->be, lca->conn );
1878 ldap_chain_connection_destroy(
1883 slap_overinst *on = (slap_overinst *) be->bd_info;
1884 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1885 void *private = be->be_private;
1886 ldap_chain_conn_apply_t lca;
1889 be->be_private = NULL;
1892 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1893 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1894 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1895 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1896 be->be_private = private;
1901 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1903 ldap_chain_parse_ctrl(
1913 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1914 rs->sr_text = "Chaining behavior control specified multiple times";
1915 return LDAP_PROTOCOL_ERROR;
1918 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1919 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1920 return LDAP_PROTOCOL_ERROR;
1923 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1924 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1929 /* Parse the control value
1930 * ChainingBehavior ::= SEQUENCE {
1931 * resolveBehavior Behavior OPTIONAL,
1932 * continuationBehavior Behavior OPTIONAL }
1934 * Behavior :: = ENUMERATED {
1935 * chainingPreferred (0),
1936 * chainingRequired (1),
1937 * referralsPreferred (2),
1938 * referralsRequired (3) }
1941 ber = ber_init( &ctrl->ldctl_value );
1943 rs->sr_text = "internal error";
1947 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1948 /* FIXME: since the whole SEQUENCE is optional,
1949 * should we accept no enumerations at all? */
1950 if ( tag != LBER_ENUMERATED ) {
1951 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1952 return LDAP_PROTOCOL_ERROR;
1955 switch ( behavior ) {
1956 case LDAP_CHAINING_PREFERRED:
1957 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1960 case LDAP_CHAINING_REQUIRED:
1961 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1964 case LDAP_REFERRALS_PREFERRED:
1965 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1968 case LDAP_REFERRALS_REQUIRED:
1969 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1973 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1974 return LDAP_PROTOCOL_ERROR;
1977 tag = ber_peek_tag( ber, &len );
1978 if ( tag == LBER_ENUMERATED ) {
1979 tag = ber_scanf( ber, "e", &behavior );
1980 if ( tag == LBER_ERROR ) {
1981 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1982 return LDAP_PROTOCOL_ERROR;
1986 if ( tag == LBER_DEFAULT ) {
1987 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1990 switch ( behavior ) {
1991 case LDAP_CHAINING_PREFERRED:
1992 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1995 case LDAP_CHAINING_REQUIRED:
1996 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1999 case LDAP_REFERRALS_PREFERRED:
2000 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2003 case LDAP_REFERRALS_REQUIRED:
2004 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2008 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2009 return LDAP_PROTOCOL_ERROR;
2013 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2014 rs->sr_text = "Chaining behavior control: decoding error";
2015 return LDAP_PROTOCOL_ERROR;
2018 (void) ber_free( ber, 1 );
2021 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2022 ? SLAP_CONTROL_CRITICAL
2023 : SLAP_CONTROL_NONCRITICAL );
2025 return LDAP_SUCCESS;
2027 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2029 static slap_overinst ldapchain;
2036 /* Make sure we don't exceed the bits reserved for userland */
2037 config_check_userland( CH_LAST );
2039 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2040 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2041 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2042 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2043 if ( rc != LDAP_SUCCESS ) {
2044 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2045 "unable to register chaining behavior control: %d.\n",
2049 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2051 ldapchain.on_bi.bi_type = "chain";
2052 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2053 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2054 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2055 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2056 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2058 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2060 ldapchain.on_response = ldap_chain_response;
2062 ldapchain.on_bi.bi_cf_ocs = chainocs;
2064 rc = config_register_schema( chaincfg, chainocs );
2069 return overlay_register( &ldapchain );