1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2007 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 LDAPURLDesc *srv = NULL;
418 struct berval save_req_dn = op->o_req_dn,
419 save_req_ndn = op->o_req_ndn,
425 /* We're setting the URI of the first referral;
426 * what if there are more?
432 If the client wishes to progress the operation, it MUST follow the
433 referral by contacting one of the supported services. If multiple
434 URIs are present, the client assumes that any supported URI may be
435 used to progress the operation.
437 * so we actually need to follow exactly one,
438 * and we can assume any is fine.
441 /* parse reference and use
442 * proto://[host][:port]/ only */
443 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
444 if ( rc != LDAP_URL_SUCCESS ) {
451 ber_str2bv( srv->lud_dn, 0, 0, &dn );
452 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
453 if ( rc == LDAP_SUCCESS ) {
454 /* remove DN essentially because later on
455 * ldap_initialize() will parse the URL
456 * as a comma-separated URL list */
458 srv->lud_scope = LDAP_SCOPE_DEFAULT;
459 li.li_uri = ldap_url_desc2str( srv );
460 srv->lud_dn = dn.bv_val;
462 ldap_free_urldesc( srv );
464 if ( rc != LDAP_SUCCESS ) {
470 if ( li.li_uri == NULL ) {
473 goto further_cleanup;
479 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
481 /* Searches for a ldapinfo in the avl tree */
482 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
483 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
484 (caddr_t)&li, ldap_chain_uri_cmp );
485 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
488 op->o_bd->be_private = (void *)lip;
491 rc = ldap_chain_db_init_one( op->o_bd );
495 lip = (ldapinfo_t *)op->o_bd->be_private;
496 lip->li_uri = li.li_uri;
497 lip->li_bvuri = bvuri;
498 rc = ldap_chain_db_open_one( op->o_bd );
501 lip->li_bvuri = NULL;
502 (void)ldap_chain_db_destroy_one( op->o_bd );
506 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
507 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
508 if ( avl_insert( &lc->lc_lai.lai_tree,
509 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
511 /* someone just inserted another;
512 * don't bother, use this and then
516 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
524 lb->lb_depth = depth + 1;
528 /* note the first error */
529 if ( first_rc == -1 ) {
534 ldap_memfree( li.li_uri );
539 lip->li_bvuri = NULL;
540 (void)ldap_chain_db_close_one( op->o_bd );
541 (void)ldap_chain_db_destroy_one( op->o_bd );
545 if ( !BER_BVISNULL( &pdn ) ) {
546 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
548 op->o_req_dn = save_req_dn;
550 if ( !BER_BVISNULL( &ndn ) ) {
551 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
553 op->o_req_ndn = save_req_ndn;
555 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
560 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
561 (void)chaining_control_remove( op, &ctrls );
562 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
564 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
579 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
580 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
581 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
582 ldapinfo_t li = { 0 }, *lip = NULL;
583 struct berval bvuri[ 2 ] = { { 0 } };
585 struct berval odn = op->o_req_dn,
586 ondn = op->o_req_ndn;
587 slap_response *save_response = op->o_callback->sc_response;
592 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
593 LDAPControl **ctrls = NULL;
595 (void)chaining_control_add( lc, op, &ctrls );
596 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
598 rs->sr_type = REP_SEARCH;
600 op->o_callback->sc_response = ldap_chain_cb_search_response;
602 /* if we parse the URI then by no means
603 * we can cache stuff or reuse connections,
604 * because in back-ldap there's no caching
605 * based on the URI value, which is supposed
606 * to be set once for all (correct?) */
608 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
610 struct berval save_req_dn = op->o_req_dn,
611 save_req_ndn = op->o_req_ndn,
617 /* parse reference and use
618 * proto://[host][:port]/ only */
619 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
620 if ( rc != LDAP_URL_SUCCESS ) {
622 rs->sr_err = LDAP_OTHER;
627 ber_str2bv( srv->lud_dn, 0, 0, &dn );
628 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
629 if ( rc == LDAP_SUCCESS ) {
630 /* remove DN essentially because later on
631 * ldap_initialize() will parse the URL
632 * as a comma-separated URL list */
634 srv->lud_scope = LDAP_SCOPE_DEFAULT;
635 li.li_uri = ldap_url_desc2str( srv );
636 srv->lud_dn = dn.bv_val;
638 ldap_free_urldesc( srv );
640 if ( rc != LDAP_SUCCESS ) {
646 if ( li.li_uri == NULL ) {
649 goto further_cleanup;
655 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
657 /* Searches for a ldapinfo in the avl tree */
658 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
659 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
660 (caddr_t)&li, ldap_chain_uri_cmp );
661 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
664 op->o_bd->be_private = (void *)lip;
667 /* if none is found, create a temporary... */
668 rc = ldap_chain_db_init_one( op->o_bd );
672 lip = (ldapinfo_t *)op->o_bd->be_private;
673 lip->li_uri = li.li_uri;
674 lip->li_bvuri = bvuri;
675 rc = ldap_chain_db_open_one( op->o_bd );
678 lip->li_bvuri = NULL;
679 (void)ldap_chain_db_destroy_one( op->o_bd );
683 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
684 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
685 if ( avl_insert( &lc->lc_lai.lai_tree,
686 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
688 /* someone just inserted another;
689 * don't bother, use this and then
693 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
700 lb->lb_op_f = lback->bi_op_search;
701 lb->lb_depth = depth + 1;
703 /* FIXME: should we also copy filter and scope?
704 * according to RFC3296, no */
705 rc = lback->bi_op_search( op, rs );
706 if ( first_rc == -1 ) {
711 ldap_memfree( li.li_uri );
714 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
715 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
719 lip->li_bvuri = NULL;
720 (void)ldap_chain_db_close_one( op->o_bd );
721 (void)ldap_chain_db_destroy_one( op->o_bd );
725 if ( !BER_BVISNULL( &pdn ) ) {
726 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
728 op->o_req_dn = save_req_dn;
730 if ( !BER_BVISNULL( &ndn ) ) {
731 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
733 op->o_req_ndn = save_req_ndn;
735 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
742 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
743 (void)chaining_control_remove( op, &ctrls );
744 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
747 op->o_req_ndn = ondn;
748 op->o_callback->sc_response = save_response;
749 rs->sr_type = REP_SEARCHREF;
752 if ( rc != LDAP_SUCCESS ) {
753 /* couldn't chase any of the referrals */
754 if ( first_rc != -1 ) {
758 rc = SLAP_CB_CONTINUE;
766 ldap_chain_response( Operation *op, SlapReply *rs )
768 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
769 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
770 BackendDB db, *bd = op->o_bd;
771 ldap_chain_cb_t lb = { 0 };
772 slap_callback *sc = op->o_callback,
777 struct berval ndn = op->o_ndn;
779 int sr_err = rs->sr_err;
780 slap_reply_t sr_type = rs->sr_type;
781 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
782 slap_mask_t chain_mask = 0;
783 ber_len_t chain_shift = 0;
784 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
786 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
787 return SLAP_CB_CONTINUE;
790 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
791 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
792 switch ( get_resolveBehavior( op ) ) {
793 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
794 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
795 return SLAP_CB_CONTINUE;
798 chain_mask = SLAP_CH_RESOLVE_MASK;
799 chain_shift = SLAP_CH_RESOLVE_SHIFT;
803 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
804 switch ( get_continuationBehavior( op ) ) {
805 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
806 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
807 return SLAP_CB_CONTINUE;
810 chain_mask = SLAP_CH_CONTINUATION_MASK;
811 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
815 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
818 * TODO: add checks on who/when chain operations; e.g.:
819 * a) what identities are authorized
820 * b) what request DN (e.g. only chain requests rooted at <DN>)
821 * c) what referral URIs
822 * d) what protocol scheme (e.g. only ldaps://)
827 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
830 matched = rs->sr_matched;
831 rs->sr_matched = NULL;
835 /* we need this to know if back-ldap returned any result */
837 sc2.sc_private = &lb;
838 sc2.sc_response = ldap_chain_cb_response;
839 op->o_callback = &sc2;
841 /* Chaining can be performed by a privileged user on behalf
842 * of normal users, using the ProxyAuthz control, by exploiting
843 * the identity assertion feature of back-ldap; see idassert-*
844 * directives in slapd-ldap(5).
846 * FIXME: the idassert-authcDN is one, will it be fine regardless
847 * of the URI we obtain from the referral?
850 switch ( op->o_tag ) {
851 case LDAP_REQ_BIND: {
852 struct berval rndn = op->o_req_ndn;
853 Connection *conn = op->o_conn;
855 /* FIXME: can we really get a referral for binds? */
856 op->o_req_ndn = slap_empty_bv;
858 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
859 op->o_req_ndn = rndn;
865 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
868 case LDAP_REQ_DELETE:
869 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
872 case LDAP_REQ_MODRDN:
873 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
876 case LDAP_REQ_MODIFY:
877 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
880 case LDAP_REQ_COMPARE:
881 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
882 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
887 case LDAP_REQ_SEARCH:
888 if ( rs->sr_type == REP_SEARCHREF ) {
889 rc = ldap_chain_search( op, rs, ref, 0 );
892 /* we might get here before any database actually
893 * performed a search; in those cases, we need
894 * to check limits, to make sure safe defaults
896 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
897 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
900 rc = SLAP_CB_CONTINUE;
905 case LDAP_REQ_EXTENDED:
906 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
907 /* FIXME: ldap_back_extended() by design
908 * doesn't send result; frontend is expected
910 /* FIXME: what about chaining? */
911 if ( rc != SLAPD_ABANDON ) {
912 send_ldap_extended( op, rs );
915 lb.lb_status = LDAP_CH_RES;
919 rc = SLAP_CB_CONTINUE;
929 /* slapd-ldap sent response */
930 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
931 /* FIXME: should we send response? */
932 Debug( LDAP_DEBUG_ANY,
933 "%s: ldap_chain_response: "
934 "overlay should have sent result.\n",
935 op->o_log_prefix, 0, 0 );
940 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
941 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
945 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
946 case LDAP_CHAINING_REQUIRED:
948 op->o_callback = NULL;
949 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
950 "operation cannot be completed without chaining" );
954 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
955 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
957 rs->sr_type = sr_type;
960 rc = SLAP_CB_CONTINUE;
962 rs->sr_type = sr_type;
963 rs->sr_matched = matched;
966 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
969 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
972 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
973 op->o_callback = NULL;
974 rc = rs->sr_err = slap_map_api2result( rs );
975 send_ldap_result( op, rs );
980 rs->sr_type = sr_type;
981 rs->sr_matched = matched;
990 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
992 ldap_chain_parse_ctrl(
998 str2chain( const char *s )
1000 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1001 return LDAP_CHAINING_PREFERRED;
1003 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1004 return LDAP_CHAINING_REQUIRED;
1006 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1007 return LDAP_REFERRALS_PREFERRED;
1009 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1010 return LDAP_REFERRALS_REQUIRED;
1015 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1030 static ConfigDriver chain_cf_gen;
1031 static ConfigCfAdd chain_cfadd;
1032 static ConfigLDAPadd chain_ldadd;
1034 static ConfigTable chaincfg[] = {
1035 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1036 { "chain-chaining", "args",
1037 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1038 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1039 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1040 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1041 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1042 { "chain-cache-uri", "TRUE/FALSE",
1043 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1044 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1045 "DESC 'Enables caching of URIs not present in configuration' "
1046 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1047 { "chain-max-depth", "args",
1048 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1049 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1050 "DESC 'max referral depth' "
1051 "SYNTAX OMsInteger "
1052 "EQUALITY integerMatch "
1053 "SINGLE-VALUE )", NULL, NULL },
1054 { "chain-return-error", "TRUE/FALSE",
1055 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1056 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1057 "DESC 'Errors are returned instead of the original referral' "
1058 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1059 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1062 static ConfigOCs chainocs[] = {
1063 { "( OLcfgOvOc:3.1 "
1064 "NAME 'olcChainConfig' "
1065 "DESC 'Chain configuration' "
1066 "SUP olcOverlayConfig "
1068 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1069 "olcChainingBehavior $ "
1070 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1071 "olcChainCacheURI $ "
1072 "olcChainMaxReferralDepth $ "
1073 "olcChainReturnError "
1075 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1076 { "( OLcfgOvOc:3.2 "
1077 "NAME 'olcChainDatabase' "
1078 "DESC 'Chain remote server configuration' "
1080 Cft_Misc, chaincfg, chain_ldadd },
1085 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1092 AttributeDescription *ad = NULL;
1098 if ( p->ce_type != Cft_Overlay
1100 || p->ce_bi->bi_cf_ocs != chainocs )
1102 return LDAP_CONSTRAINT_VIOLATION;
1105 on = (slap_overinst *)p->ce_bi;
1106 lc = (ldap_chain_t *)on->on_bi.bi_private;
1108 assert( ca->be == NULL );
1109 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1111 ca->be->bd_info = (BackendInfo *)on;
1113 rc = slap_str2ad( "olcDbURI", &ad, &text );
1114 assert( rc == LDAP_SUCCESS );
1116 at = attr_find( e->e_attrs, ad );
1117 if ( lc->lc_common_li == NULL && at != NULL ) {
1118 /* FIXME: we should generate an empty default entry
1119 * if none is supplied */
1120 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1121 "first underlying database \"%s\" "
1122 "cannot contain attribute \"%s\".\n",
1123 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1124 rc = LDAP_CONSTRAINT_VIOLATION;
1127 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1128 /* FIXME: we should generate an empty default entry
1129 * if none is supplied */
1130 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1131 "subsequent underlying database \"%s\" "
1132 "must contain attribute \"%s\".\n",
1133 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1134 rc = LDAP_CONSTRAINT_VIOLATION;
1138 if ( lc->lc_common_li == NULL ) {
1139 rc = ldap_chain_db_init_common( ca->be );
1142 rc = ldap_chain_db_init_one( ca->be );
1146 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1147 "unable to init %sunderlying database \"%s\".\n",
1148 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1149 return LDAP_CONSTRAINT_VIOLATION;
1152 li = ca->be->be_private;
1154 if ( lc->lc_common_li == NULL ) {
1155 lc->lc_common_li = li;
1158 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1159 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1160 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1161 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1163 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1164 "database \"%s\" insert failed.\n",
1165 e->e_name.bv_val, 0, 0 );
1166 rc = LDAP_CONSTRAINT_VIOLATION;
1172 if ( rc != LDAP_SUCCESS ) {
1173 (void)ldap_chain_db_destroy_one( ca->be );
1181 typedef struct ldap_chain_cfadd_apply_t {
1187 } ldap_chain_cfadd_apply_t;
1190 ldap_chain_cfadd_apply( void *datum, void *arg )
1192 ldapinfo_t *li = (ldapinfo_t *)datum;
1193 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1197 /* FIXME: should not hardcode "olcDatabase" here */
1198 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1199 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1200 bv.bv_val = lca->ca->msg;
1202 lca->ca->be->be_private = (void *)li;
1203 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1204 &bv, lback->bi_cf_ocs, &chainocs[1] );
1212 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1214 CfEntryInfo *pe = p->e_private;
1215 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1216 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1217 void *priv = (void *)ca->be->be_private;
1219 if ( lback->bi_cf_ocs ) {
1220 ldap_chain_cfadd_apply_t lca = { 0 };
1228 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1230 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1231 &lca, 1, AVL_INORDER );
1233 ca->be->be_private = priv;
1239 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1240 static slap_verbmasks chaining_mode[] = {
1241 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1242 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1243 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1244 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1247 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1250 chain_cf_gen( ConfigArgs *c )
1252 slap_overinst *on = (slap_overinst *)c->bi;
1253 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1257 if ( c->op == SLAP_CONFIG_EMIT ) {
1259 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1261 struct berval resolve = BER_BVNULL,
1262 continuation = BER_BVNULL;
1264 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1268 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1269 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1271 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1273 + STRLENOF( "continuation=" ) + continuation.bv_len;
1274 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1275 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1276 "resolve=%s continuation=%s",
1277 resolve.bv_val, continuation.bv_val );
1279 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1280 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1281 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1282 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1283 " critical", STRLENOF( " critical" ) + 1 );
1284 c->value_bv.bv_len += STRLENOF( " critical" );
1289 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1292 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1296 c->value_int = lc->lc_max_depth;
1300 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1309 } else if ( c->op == LDAP_MOD_DELETE ) {
1315 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1323 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1334 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1335 char **argv = c->argv;
1337 BerElementBuffer berbuf;
1338 BerElement *ber = (BerElement *)&berbuf;
1342 Operation op = { 0 };
1343 SlapReply rs = { 0 };
1345 lc->lc_chaining_ctrlflag = 0;
1347 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1348 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1349 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1350 if ( resolve == -1 ) {
1351 Debug( LDAP_DEBUG_ANY, "%s: "
1352 "illegal <resolve> value %s "
1353 "in \"chain-chaining>\".\n",
1354 c->log, argv[ 0 ], 0 );
1358 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1359 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1360 if ( continuation == -1 ) {
1361 Debug( LDAP_DEBUG_ANY, "%s: "
1362 "illegal <continuation> value %s "
1363 "in \"chain-chaining\".\n",
1364 c->log, argv[ 0 ], 0 );
1368 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1372 Debug( LDAP_DEBUG_ANY, "%s: "
1373 "unknown option in \"chain-chaining\".\n",
1379 if ( resolve != -1 || continuation != -1 ) {
1382 if ( resolve == -1 ) {
1384 resolve = SLAP_CHAINING_DEFAULT;
1387 ber_init2( ber, NULL, LBER_USE_DER );
1389 err = ber_printf( ber, "{e" /* } */, resolve );
1392 Debug( LDAP_DEBUG_ANY, "%s: "
1393 "chaining behavior control encoding error!\n",
1398 if ( continuation > -1 ) {
1399 err = ber_printf( ber, "e", continuation );
1402 Debug( LDAP_DEBUG_ANY, "%s: "
1403 "chaining behavior control encoding error!\n",
1409 err = ber_printf( ber, /* { */ "N}" );
1412 Debug( LDAP_DEBUG_ANY, "%s: "
1413 "chaining behavior control encoding error!\n",
1418 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1419 exit( EXIT_FAILURE );
1423 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1426 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1427 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1429 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1431 Debug( LDAP_DEBUG_ANY, "%s: "
1432 "unable to parse chaining control%s%s.\n",
1433 c->log, rs.sr_text ? ": " : "",
1434 rs.sr_text ? rs.sr_text : "" );
1438 lc->lc_chaining_ctrlflag = op.o_chaining;
1440 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1443 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1444 Debug( LDAP_DEBUG_ANY, "%s: "
1445 "\"chaining\" control unsupported (ignored).\n",
1447 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1451 if ( c->value_int ) {
1452 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1454 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1459 if ( c->value_int < 0 ) {
1460 snprintf( c->msg, sizeof( c->msg ),
1461 "<%s> invalid max referral depth %d",
1462 c->argv[0], c->value_int );
1463 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1464 c->log, c->msg, 0 );
1468 lc->lc_max_depth = c->value_int;
1471 if ( c->value_int ) {
1472 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1474 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1489 slap_overinst *on = (slap_overinst *)be->bd_info;
1490 ldap_chain_t *lc = NULL;
1492 if ( lback == NULL ) {
1493 static BackendInfo lback2;
1495 lback = backend_info( "ldap" );
1497 if ( lback == NULL ) {
1502 lback2.bi_type = ldapchain.on_bi.bi_type;
1506 lc = ch_malloc( sizeof( ldap_chain_t ) );
1510 memset( lc, 0, sizeof( ldap_chain_t ) );
1511 lc->lc_max_depth = 1;
1512 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1514 on->on_bi.bi_private = (void *)lc;
1520 ldap_chain_db_config(
1527 slap_overinst *on = (slap_overinst *)be->bd_info;
1528 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1530 int rc = SLAP_CONF_UNKNOWN;
1532 if ( lc->lc_common_li == NULL ) {
1533 void *be_private = be->be_private;
1534 ldap_chain_db_init_common( be );
1535 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1536 be->be_private = be_private;
1539 /* Something for the chain database? */
1540 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1541 char *save_argv0 = argv[ 0 ];
1542 BackendInfo *bd_info = be->bd_info;
1543 void *be_private = be->be_private;
1544 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1545 static char *allowed_argv[] = {
1546 /* special: put URI here, so in the meanwhile
1547 * it detects whether a new URI is being provided */
1553 /* FIXME: maybe rebind-as-user should be allowed
1554 * only within known URIs... */
1561 int which_argv = -1;
1563 argv[ 0 ] += STRLENOF( "chain-" );
1565 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1566 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1571 if ( allowed_argv[ which_argv ] == NULL ) {
1574 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1575 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1576 "\"%s\" only allowed within a URI directive.\n.",
1577 fname, lineno, argv[ 0 ] );
1582 if ( which_argv == 0 ) {
1583 rc = ldap_chain_db_init_one( be );
1585 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1586 "underlying slapd-ldap initialization failed.\n.",
1590 lc->lc_cfg_li = be->be_private;
1593 /* TODO: add checks on what other slapd-ldap(5) args
1594 * should be put in the template; this is not quite
1595 * harmful, because attributes that shouldn't don't
1596 * get actually used, but the user should at least
1600 be->bd_info = lback;
1601 be->be_private = (void *)lc->lc_cfg_li;
1602 be->be_cf_ocs = lback->bi_cf_ocs;
1604 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1606 argv[ 0 ] = save_argv0;
1607 be->be_cf_ocs = be_cf_ocs;
1608 be->be_private = be_private;
1609 be->bd_info = bd_info;
1611 if ( which_argv == 0 ) {
1617 db.be_private = (void *)lc->lc_cfg_li;
1618 ldap_chain_db_destroy_one( &db );
1619 lc->lc_cfg_li = NULL;
1622 if ( lc->lc_cfg_li->li_bvuri == NULL
1623 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1624 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1626 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1627 "no URI list allowed in slapo-chain.\n",
1630 goto private_destroy;
1633 if ( avl_insert( &lc->lc_lai.lai_tree,
1634 (caddr_t)lc->lc_cfg_li,
1635 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1637 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1638 "duplicate URI in slapo-chain.\n",
1641 goto private_destroy;
1658 typedef struct ldap_chain_db_apply_t {
1661 } ldap_chain_db_apply_t;
1664 ldap_chain_db_apply( void *datum, void *arg )
1666 ldapinfo_t *li = (ldapinfo_t *)datum;
1667 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1669 lca->be->be_private = (void *)li;
1671 return lca->func( lca->be );
1680 slap_overinst *on = (slap_overinst *)be->bd_info;
1681 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1686 BI_db_func *func = (&lback->bi_db_open)[ which ];
1688 if ( func != NULL && lc->lc_common_li != NULL ) {
1692 db.be_private = lc->lc_common_li;
1700 if ( lc->lc_lai.lai_tree != NULL ) {
1701 ldap_chain_db_apply_t lca;
1706 rc = avl_apply( lc->lc_lai.lai_tree,
1707 ldap_chain_db_apply, (void *)&lca,
1708 1, AVL_INORDER ) != AVL_NOMORE;
1720 slap_overinst *on = (slap_overinst *) be->bd_info;
1721 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1722 slap_mask_t monitoring;
1725 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1726 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1730 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1732 if ( lc->lc_common_li == NULL ) {
1733 void *be_private = be->be_private;
1734 ldap_chain_db_init_common( be );
1735 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1736 be->be_private = be_private;
1739 /* filter out and restore monitoring */
1740 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1741 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1742 rc = ldap_chain_db_func( be, db_open );
1743 SLAP_DBFLAGS( be ) |= monitoring;
1749 ldap_chain_db_close(
1752 return ldap_chain_db_func( be, db_close );
1756 ldap_chain_db_destroy(
1759 slap_overinst *on = (slap_overinst *) be->bd_info;
1760 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1764 rc = ldap_chain_db_func( be, db_destroy );
1767 avl_free( lc->lc_lai.lai_tree, NULL );
1768 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1776 * inits one instance of the slapd-ldap backend, and stores
1777 * the private info in be_private of the arg
1780 ldap_chain_db_init_common(
1783 BackendInfo *bi = be->bd_info;
1787 be->bd_info = lback;
1788 be->be_private = NULL;
1789 rc = lback->bi_db_init( be );
1793 li = (ldapinfo_t *)be->be_private;
1794 li->li_urllist_f = NULL;
1795 li->li_urllist_p = NULL;
1803 * inits one instance of the slapd-ldap backend, stores
1804 * the private info in be_private of the arg and fills
1805 * selected fields with data from the template.
1807 * NOTE: add checks about the other fields of the template,
1808 * which are ignored and SHOULD NOT be configured by the user.
1811 ldap_chain_db_init_one(
1814 slap_overinst *on = (slap_overinst *)be->bd_info;
1815 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1817 BackendInfo *bi = be->bd_info;
1822 be->bd_info = lback;
1823 be->be_private = NULL;
1824 t = lback->bi_db_init( be );
1828 li = (ldapinfo_t *)be->be_private;
1829 li->li_urllist_f = NULL;
1830 li->li_urllist_p = NULL;
1832 /* copy common data */
1833 li->li_nretries = lc->lc_common_li->li_nretries;
1834 li->li_flags = lc->lc_common_li->li_flags;
1835 li->li_version = lc->lc_common_li->li_version;
1836 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1837 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1845 ldap_chain_db_open_one(
1848 if ( SLAP_DBMONITORING( be ) ) {
1849 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1851 if ( li->li_uri == NULL ) {
1852 ber_str2bv( "cn=Common Connections", 0, 1,
1853 &li->li_monitor_info.lmi_rdn );
1858 li->li_monitor_info.lmi_rdn.bv_len
1859 = STRLENOF( "cn=" ) + strlen( li->li_uri );
1860 ptr = li->li_monitor_info.lmi_rdn.bv_val
1861 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
1862 ptr = lutil_strcopy( ptr, "cn=" );
1863 ptr = lutil_strcopy( ptr, li->li_uri );
1868 return lback->bi_db_open( be );
1871 typedef struct ldap_chain_conn_apply_t {
1874 } ldap_chain_conn_apply_t;
1877 ldap_chain_conn_apply( void *datum, void *arg )
1879 ldapinfo_t *li = (ldapinfo_t *)datum;
1880 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1882 lca->be->be_private = (void *)li;
1884 return lback->bi_connection_destroy( lca->be, lca->conn );
1888 ldap_chain_connection_destroy(
1893 slap_overinst *on = (slap_overinst *) be->bd_info;
1894 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1895 void *private = be->be_private;
1896 ldap_chain_conn_apply_t lca;
1899 be->be_private = NULL;
1902 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1903 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1904 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1905 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1906 be->be_private = private;
1911 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1913 ldap_chain_parse_ctrl(
1923 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1924 rs->sr_text = "Chaining behavior control specified multiple times";
1925 return LDAP_PROTOCOL_ERROR;
1928 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1929 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1930 return LDAP_PROTOCOL_ERROR;
1933 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1934 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1939 /* Parse the control value
1940 * ChainingBehavior ::= SEQUENCE {
1941 * resolveBehavior Behavior OPTIONAL,
1942 * continuationBehavior Behavior OPTIONAL }
1944 * Behavior :: = ENUMERATED {
1945 * chainingPreferred (0),
1946 * chainingRequired (1),
1947 * referralsPreferred (2),
1948 * referralsRequired (3) }
1951 ber = ber_init( &ctrl->ldctl_value );
1953 rs->sr_text = "internal error";
1957 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1958 /* FIXME: since the whole SEQUENCE is optional,
1959 * should we accept no enumerations at all? */
1960 if ( tag != LBER_ENUMERATED ) {
1961 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1962 return LDAP_PROTOCOL_ERROR;
1965 switch ( behavior ) {
1966 case LDAP_CHAINING_PREFERRED:
1967 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1970 case LDAP_CHAINING_REQUIRED:
1971 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1974 case LDAP_REFERRALS_PREFERRED:
1975 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1978 case LDAP_REFERRALS_REQUIRED:
1979 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1983 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1984 return LDAP_PROTOCOL_ERROR;
1987 tag = ber_peek_tag( ber, &len );
1988 if ( tag == LBER_ENUMERATED ) {
1989 tag = ber_scanf( ber, "e", &behavior );
1990 if ( tag == LBER_ERROR ) {
1991 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1992 return LDAP_PROTOCOL_ERROR;
1996 if ( tag == LBER_DEFAULT ) {
1997 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2000 switch ( behavior ) {
2001 case LDAP_CHAINING_PREFERRED:
2002 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2005 case LDAP_CHAINING_REQUIRED:
2006 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2009 case LDAP_REFERRALS_PREFERRED:
2010 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2013 case LDAP_REFERRALS_REQUIRED:
2014 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2018 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2019 return LDAP_PROTOCOL_ERROR;
2023 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2024 rs->sr_text = "Chaining behavior control: decoding error";
2025 return LDAP_PROTOCOL_ERROR;
2028 (void) ber_free( ber, 1 );
2031 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2032 ? SLAP_CONTROL_CRITICAL
2033 : SLAP_CONTROL_NONCRITICAL );
2035 return LDAP_SUCCESS;
2037 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2040 chain_initialize( void )
2044 /* Make sure we don't exceed the bits reserved for userland */
2045 config_check_userland( CH_LAST );
2047 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2048 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2049 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2050 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2051 if ( rc != LDAP_SUCCESS ) {
2052 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2053 "unable to register chaining behavior control: %d.\n",
2057 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2059 ldapchain.on_bi.bi_type = "chain";
2060 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2061 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2062 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2063 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2064 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2066 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2068 ldapchain.on_response = ldap_chain_response;
2070 ldapchain.on_bi.bi_cf_ocs = chainocs;
2072 rc = config_register_schema( chaincfg, chainocs );
2077 return overlay_register( &ldapchain );