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 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, LDAP_PVT_URL_PARSE_NONE );
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, LDAP_PVT_URL_PARSE_NONE );
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 );
729 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
730 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
734 lip->li_bvuri = NULL;
735 (void)ldap_chain_db_close_one( op->o_bd );
736 (void)ldap_chain_db_destroy_one( op->o_bd );
740 if ( !BER_BVISNULL( &pdn ) ) {
741 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
743 op->o_req_dn = save_req_dn;
745 if ( !BER_BVISNULL( &ndn ) ) {
746 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
748 op->o_req_ndn = save_req_ndn;
750 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
758 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
759 (void)chaining_control_remove( op, &ctrls );
760 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
763 op->o_req_ndn = ondn;
764 op->o_callback->sc_response = save_response;
765 rs->sr_type = REP_SEARCHREF;
768 if ( rc != LDAP_SUCCESS ) {
769 /* couldn't chase any of the referrals */
770 if ( first_rc != -1 ) {
774 rc = SLAP_CB_CONTINUE;
782 ldap_chain_response( Operation *op, SlapReply *rs )
784 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
785 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
786 BackendDB db, *bd = op->o_bd;
787 ldap_chain_cb_t lb = { 0 };
788 slap_callback *sc = op->o_callback,
791 const char *text = NULL;
794 struct berval ndn = op->o_ndn;
796 int sr_err = rs->sr_err;
797 slap_reply_t sr_type = rs->sr_type;
798 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
799 slap_mask_t chain_mask = 0;
800 ber_len_t chain_shift = 0;
801 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
803 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
804 return SLAP_CB_CONTINUE;
807 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
808 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
809 switch ( get_resolveBehavior( op ) ) {
810 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
811 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
812 return SLAP_CB_CONTINUE;
815 chain_mask = SLAP_CH_RESOLVE_MASK;
816 chain_shift = SLAP_CH_RESOLVE_SHIFT;
820 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
821 switch ( get_continuationBehavior( op ) ) {
822 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
823 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
824 return SLAP_CB_CONTINUE;
827 chain_mask = SLAP_CH_CONTINUATION_MASK;
828 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
832 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
835 * TODO: add checks on who/when chain operations; e.g.:
836 * a) what identities are authorized
837 * b) what request DN (e.g. only chain requests rooted at <DN>)
838 * c) what referral URIs
839 * d) what protocol scheme (e.g. only ldaps://)
844 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
849 matched = rs->sr_matched;
850 rs->sr_matched = NULL;
854 /* we need this to know if back-ldap returned any result */
856 sc2.sc_private = &lb;
857 sc2.sc_response = ldap_chain_cb_response;
858 op->o_callback = &sc2;
860 /* Chaining can be performed by a privileged user on behalf
861 * of normal users, using the ProxyAuthz control, by exploiting
862 * the identity assertion feature of back-ldap; see idassert-*
863 * directives in slapd-ldap(5).
865 * FIXME: the idassert-authcDN is one, will it be fine regardless
866 * of the URI we obtain from the referral?
869 switch ( op->o_tag ) {
870 case LDAP_REQ_BIND: {
871 struct berval rndn = op->o_req_ndn;
872 Connection *conn = op->o_conn;
874 /* FIXME: can we really get a referral for binds? */
875 op->o_req_ndn = slap_empty_bv;
877 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
878 op->o_req_ndn = rndn;
884 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
887 case LDAP_REQ_DELETE:
888 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
891 case LDAP_REQ_MODRDN:
892 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
895 case LDAP_REQ_MODIFY:
896 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
899 case LDAP_REQ_COMPARE:
900 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
901 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
906 case LDAP_REQ_SEARCH:
907 if ( rs->sr_type == REP_SEARCHREF ) {
908 rc = ldap_chain_search( op, rs, ref, 0 );
911 /* we might get here before any database actually
912 * performed a search; in those cases, we need
913 * to check limits, to make sure safe defaults
915 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
916 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
919 rc = SLAP_CB_CONTINUE;
924 case LDAP_REQ_EXTENDED:
925 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
926 /* FIXME: ldap_back_extended() by design
927 * doesn't send result; frontend is expected
929 /* FIXME: what about chaining? */
930 if ( rc != SLAPD_ABANDON ) {
932 send_ldap_extended( op, rs );
935 lb.lb_status = LDAP_CH_RES;
939 rc = SLAP_CB_CONTINUE;
949 /* slapd-ldap sent response */
950 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
951 /* FIXME: should we send response? */
952 Debug( LDAP_DEBUG_ANY,
953 "%s: ldap_chain_response: "
954 "overlay should have sent result.\n",
955 op->o_log_prefix, 0, 0 );
960 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
961 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
965 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
966 case LDAP_CHAINING_REQUIRED:
968 op->o_callback = NULL;
969 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
970 "operation cannot be completed without chaining" );
974 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
975 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
977 rs->sr_type = sr_type;
980 rc = SLAP_CB_CONTINUE;
982 rs->sr_type = sr_type;
984 rs->sr_matched = matched;
987 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
990 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
993 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
994 op->o_callback = NULL;
995 rc = rs->sr_err = slap_map_api2result( rs );
996 send_ldap_result( op, rs );
1000 rs->sr_err = sr_err;
1001 rs->sr_type = sr_type;
1003 rs->sr_matched = matched;
1006 op->o_callback = sc;
1012 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1014 ldap_chain_parse_ctrl(
1017 LDAPControl *ctrl );
1020 str2chain( const char *s )
1022 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1023 return LDAP_CHAINING_PREFERRED;
1025 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1026 return LDAP_CHAINING_REQUIRED;
1028 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1029 return LDAP_REFERRALS_PREFERRED;
1031 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1032 return LDAP_REFERRALS_REQUIRED;
1037 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1052 static ConfigDriver chain_cf_gen;
1053 static ConfigCfAdd chain_cfadd;
1054 static ConfigLDAPadd chain_ldadd;
1056 static ConfigTable chaincfg[] = {
1057 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1058 { "chain-chaining", "args",
1059 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1060 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1061 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1062 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1063 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1064 { "chain-cache-uri", "TRUE/FALSE",
1065 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1066 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1067 "DESC 'Enables caching of URIs not present in configuration' "
1068 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1069 { "chain-max-depth", "args",
1070 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1071 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1072 "DESC 'max referral depth' "
1073 "SYNTAX OMsInteger "
1074 "EQUALITY integerMatch "
1075 "SINGLE-VALUE )", NULL, NULL },
1076 { "chain-return-error", "TRUE/FALSE",
1077 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1078 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1079 "DESC 'Errors are returned instead of the original referral' "
1080 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1081 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1084 static ConfigOCs chainocs[] = {
1085 { "( OLcfgOvOc:3.1 "
1086 "NAME 'olcChainConfig' "
1087 "DESC 'Chain configuration' "
1088 "SUP olcOverlayConfig "
1090 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1091 "olcChainingBehavior $ "
1092 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1093 "olcChainCacheURI $ "
1094 "olcChainMaxReferralDepth $ "
1095 "olcChainReturnError "
1097 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1098 { "( OLcfgOvOc:3.2 "
1099 "NAME 'olcChainDatabase' "
1100 "DESC 'Chain remote server configuration' "
1102 Cft_Misc, chaincfg, chain_ldadd },
1107 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1114 AttributeDescription *ad = NULL;
1120 if ( p->ce_type != Cft_Overlay
1122 || p->ce_bi->bi_cf_ocs != chainocs )
1124 return LDAP_CONSTRAINT_VIOLATION;
1127 on = (slap_overinst *)p->ce_bi;
1128 lc = (ldap_chain_t *)on->on_bi.bi_private;
1130 assert( ca->be == NULL );
1131 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1133 ca->be->bd_info = (BackendInfo *)on;
1135 rc = slap_str2ad( "olcDbURI", &ad, &text );
1136 assert( rc == LDAP_SUCCESS );
1138 at = attr_find( e->e_attrs, ad );
1139 if ( lc->lc_common_li == NULL && at != NULL ) {
1140 /* FIXME: we should generate an empty default entry
1141 * if none is supplied */
1142 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1143 "first underlying database \"%s\" "
1144 "cannot contain attribute \"%s\".\n",
1145 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1146 rc = LDAP_CONSTRAINT_VIOLATION;
1149 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1150 /* FIXME: we should generate an empty default entry
1151 * if none is supplied */
1152 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1153 "subsequent underlying database \"%s\" "
1154 "must contain attribute \"%s\".\n",
1155 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1156 rc = LDAP_CONSTRAINT_VIOLATION;
1160 if ( lc->lc_common_li == NULL ) {
1161 rc = ldap_chain_db_init_common( ca->be );
1164 rc = ldap_chain_db_init_one( ca->be );
1168 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1169 "unable to init %sunderlying database \"%s\".\n",
1170 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1171 return LDAP_CONSTRAINT_VIOLATION;
1174 li = ca->be->be_private;
1176 if ( lc->lc_common_li == NULL ) {
1177 lc->lc_common_li = li;
1180 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1181 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1182 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1183 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1185 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1186 "database \"%s\" insert failed.\n",
1187 e->e_name.bv_val, 0, 0 );
1188 rc = LDAP_CONSTRAINT_VIOLATION;
1194 if ( rc != LDAP_SUCCESS ) {
1195 (void)ldap_chain_db_destroy_one( ca->be );
1203 typedef struct ldap_chain_cfadd_apply_t {
1209 } ldap_chain_cfadd_apply_t;
1212 ldap_chain_cfadd_apply( void *datum, void *arg )
1214 ldapinfo_t *li = (ldapinfo_t *)datum;
1215 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1219 /* FIXME: should not hardcode "olcDatabase" here */
1220 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1221 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1222 bv.bv_val = lca->ca->msg;
1224 lca->ca->be->be_private = (void *)li;
1225 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1226 &bv, lback->bi_cf_ocs, &chainocs[1] );
1234 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1236 CfEntryInfo *pe = p->e_private;
1237 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1238 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1239 void *priv = (void *)ca->be->be_private;
1241 if ( lback->bi_cf_ocs ) {
1242 ldap_chain_cfadd_apply_t lca = { 0 };
1250 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1252 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1253 &lca, 1, AVL_INORDER );
1255 ca->be->be_private = priv;
1261 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1262 static slap_verbmasks chaining_mode[] = {
1263 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1264 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1265 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1266 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1269 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1272 chain_cf_gen( ConfigArgs *c )
1274 slap_overinst *on = (slap_overinst *)c->bi;
1275 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1279 if ( c->op == SLAP_CONFIG_EMIT ) {
1281 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1283 struct berval resolve = BER_BVNULL,
1284 continuation = BER_BVNULL;
1286 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1290 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1291 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1293 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1295 + STRLENOF( "continuation=" ) + continuation.bv_len;
1296 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1297 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1298 "resolve=%s continuation=%s",
1299 resolve.bv_val, continuation.bv_val );
1301 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1302 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1303 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1304 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1305 " critical", STRLENOF( " critical" ) + 1 );
1306 c->value_bv.bv_len += STRLENOF( " critical" );
1311 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1314 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1318 c->value_int = lc->lc_max_depth;
1322 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1331 } else if ( c->op == LDAP_MOD_DELETE ) {
1337 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1345 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1356 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1357 char **argv = c->argv;
1359 BerElementBuffer berbuf;
1360 BerElement *ber = (BerElement *)&berbuf;
1364 Operation op = { 0 };
1365 SlapReply rs = { 0 };
1367 lc->lc_chaining_ctrlflag = 0;
1369 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1370 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1371 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1372 if ( resolve == -1 ) {
1373 Debug( LDAP_DEBUG_ANY, "%s: "
1374 "illegal <resolve> value %s "
1375 "in \"chain-chaining>\".\n",
1376 c->log, argv[ 0 ], 0 );
1380 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1381 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1382 if ( continuation == -1 ) {
1383 Debug( LDAP_DEBUG_ANY, "%s: "
1384 "illegal <continuation> value %s "
1385 "in \"chain-chaining\".\n",
1386 c->log, argv[ 0 ], 0 );
1390 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1394 Debug( LDAP_DEBUG_ANY, "%s: "
1395 "unknown option in \"chain-chaining\".\n",
1401 if ( resolve != -1 || continuation != -1 ) {
1404 if ( resolve == -1 ) {
1406 resolve = SLAP_CHAINING_DEFAULT;
1409 ber_init2( ber, NULL, LBER_USE_DER );
1411 err = ber_printf( ber, "{e" /* } */, resolve );
1414 Debug( LDAP_DEBUG_ANY, "%s: "
1415 "chaining behavior control encoding error!\n",
1420 if ( continuation > -1 ) {
1421 err = ber_printf( ber, "e", continuation );
1424 Debug( LDAP_DEBUG_ANY, "%s: "
1425 "chaining behavior control encoding error!\n",
1431 err = ber_printf( ber, /* { */ "N}" );
1434 Debug( LDAP_DEBUG_ANY, "%s: "
1435 "chaining behavior control encoding error!\n",
1440 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1441 exit( EXIT_FAILURE );
1445 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1448 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1449 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1451 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1453 Debug( LDAP_DEBUG_ANY, "%s: "
1454 "unable to parse chaining control%s%s.\n",
1455 c->log, rs.sr_text ? ": " : "",
1456 rs.sr_text ? rs.sr_text : "" );
1460 lc->lc_chaining_ctrlflag = op.o_chaining;
1462 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1465 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1466 Debug( LDAP_DEBUG_ANY, "%s: "
1467 "\"chaining\" control unsupported (ignored).\n",
1469 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1473 if ( c->value_int ) {
1474 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1476 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1481 if ( c->value_int < 0 ) {
1482 snprintf( c->msg, sizeof( c->msg ),
1483 "<%s> invalid max referral depth %d",
1484 c->argv[0], c->value_int );
1485 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1486 c->log, c->msg, 0 );
1490 lc->lc_max_depth = c->value_int;
1493 if ( c->value_int ) {
1494 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1496 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1511 slap_overinst *on = (slap_overinst *)be->bd_info;
1512 ldap_chain_t *lc = NULL;
1514 if ( lback == NULL ) {
1515 static BackendInfo lback2;
1517 lback = backend_info( "ldap" );
1519 if ( lback == NULL ) {
1524 lback2.bi_type = ldapchain.on_bi.bi_type;
1528 lc = ch_malloc( sizeof( ldap_chain_t ) );
1532 memset( lc, 0, sizeof( ldap_chain_t ) );
1533 lc->lc_max_depth = 1;
1534 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1536 on->on_bi.bi_private = (void *)lc;
1542 ldap_chain_db_config(
1549 slap_overinst *on = (slap_overinst *)be->bd_info;
1550 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1552 int rc = SLAP_CONF_UNKNOWN;
1554 if ( lc->lc_common_li == NULL ) {
1555 void *be_private = be->be_private;
1556 ldap_chain_db_init_common( be );
1557 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1558 be->be_private = be_private;
1561 /* Something for the chain database? */
1562 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1563 char *save_argv0 = argv[ 0 ];
1564 BackendInfo *bd_info = be->bd_info;
1565 void *be_private = be->be_private;
1566 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1567 static char *allowed_argv[] = {
1568 /* special: put URI here, so in the meanwhile
1569 * it detects whether a new URI is being provided */
1575 /* FIXME: maybe rebind-as-user should be allowed
1576 * only within known URIs... */
1583 int which_argv = -1;
1585 argv[ 0 ] += STRLENOF( "chain-" );
1587 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1588 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1593 if ( allowed_argv[ which_argv ] == NULL ) {
1596 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1597 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1598 "\"%s\" only allowed within a URI directive.\n.",
1599 fname, lineno, argv[ 0 ] );
1604 if ( which_argv == 0 ) {
1605 rc = ldap_chain_db_init_one( be );
1607 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1608 "underlying slapd-ldap initialization failed.\n.",
1612 lc->lc_cfg_li = be->be_private;
1615 /* TODO: add checks on what other slapd-ldap(5) args
1616 * should be put in the template; this is not quite
1617 * harmful, because attributes that shouldn't don't
1618 * get actually used, but the user should at least
1622 be->bd_info = lback;
1623 be->be_private = (void *)lc->lc_cfg_li;
1624 be->be_cf_ocs = lback->bi_cf_ocs;
1626 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1628 argv[ 0 ] = save_argv0;
1629 be->be_cf_ocs = be_cf_ocs;
1630 be->be_private = be_private;
1631 be->bd_info = bd_info;
1633 if ( which_argv == 0 ) {
1639 db.be_private = (void *)lc->lc_cfg_li;
1640 ldap_chain_db_destroy_one( &db );
1641 lc->lc_cfg_li = NULL;
1644 if ( lc->lc_cfg_li->li_bvuri == NULL
1645 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1646 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1648 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1649 "no URI list allowed in slapo-chain.\n",
1652 goto private_destroy;
1655 if ( avl_insert( &lc->lc_lai.lai_tree,
1656 (caddr_t)lc->lc_cfg_li,
1657 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1659 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1660 "duplicate URI in slapo-chain.\n",
1663 goto private_destroy;
1680 typedef struct ldap_chain_db_apply_t {
1683 } ldap_chain_db_apply_t;
1686 ldap_chain_db_apply( void *datum, void *arg )
1688 ldapinfo_t *li = (ldapinfo_t *)datum;
1689 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1691 lca->be->be_private = (void *)li;
1693 return lca->func( lca->be );
1702 slap_overinst *on = (slap_overinst *)be->bd_info;
1703 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1708 BI_db_func *func = (&lback->bi_db_open)[ which ];
1710 if ( func != NULL && lc->lc_common_li != NULL ) {
1714 db.be_private = lc->lc_common_li;
1722 if ( lc->lc_lai.lai_tree != NULL ) {
1723 ldap_chain_db_apply_t lca;
1728 rc = avl_apply( lc->lc_lai.lai_tree,
1729 ldap_chain_db_apply, (void *)&lca,
1730 1, AVL_INORDER ) != AVL_NOMORE;
1742 slap_overinst *on = (slap_overinst *) be->bd_info;
1743 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1744 slap_mask_t monitoring;
1747 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1748 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1752 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1754 if ( lc->lc_common_li == NULL ) {
1755 void *be_private = be->be_private;
1756 ldap_chain_db_init_common( be );
1757 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1758 be->be_private = be_private;
1761 /* filter out and restore monitoring */
1762 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1763 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1764 rc = ldap_chain_db_func( be, db_open );
1765 SLAP_DBFLAGS( be ) |= monitoring;
1771 ldap_chain_db_close(
1774 return ldap_chain_db_func( be, db_close );
1778 ldap_chain_db_destroy(
1781 slap_overinst *on = (slap_overinst *) be->bd_info;
1782 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1786 rc = ldap_chain_db_func( be, db_destroy );
1789 avl_free( lc->lc_lai.lai_tree, NULL );
1790 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1798 * inits one instance of the slapd-ldap backend, and stores
1799 * the private info in be_private of the arg
1802 ldap_chain_db_init_common(
1805 BackendInfo *bi = be->bd_info;
1809 be->bd_info = lback;
1810 be->be_private = NULL;
1811 rc = lback->bi_db_init( be );
1815 li = (ldapinfo_t *)be->be_private;
1816 li->li_urllist_f = NULL;
1817 li->li_urllist_p = NULL;
1825 * inits one instance of the slapd-ldap backend, stores
1826 * the private info in be_private of the arg and fills
1827 * selected fields with data from the template.
1829 * NOTE: add checks about the other fields of the template,
1830 * which are ignored and SHOULD NOT be configured by the user.
1833 ldap_chain_db_init_one(
1836 slap_overinst *on = (slap_overinst *)be->bd_info;
1837 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1839 BackendInfo *bi = be->bd_info;
1844 be->bd_info = lback;
1845 be->be_private = NULL;
1846 t = lback->bi_db_init( be );
1850 li = (ldapinfo_t *)be->be_private;
1851 li->li_urllist_f = NULL;
1852 li->li_urllist_p = NULL;
1854 /* copy common data */
1855 li->li_nretries = lc->lc_common_li->li_nretries;
1856 li->li_flags = lc->lc_common_li->li_flags;
1857 li->li_version = lc->lc_common_li->li_version;
1858 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1859 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1867 ldap_chain_db_open_one(
1870 if ( SLAP_DBMONITORING( be ) ) {
1871 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1873 if ( li->li_uri == NULL ) {
1874 ber_str2bv( "cn=Common Connections", 0, 1,
1875 &li->li_monitor_info.lmi_rdn );
1880 li->li_monitor_info.lmi_rdn.bv_len
1881 = STRLENOF( "cn=" ) + strlen( li->li_uri );
1882 ptr = li->li_monitor_info.lmi_rdn.bv_val
1883 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
1884 ptr = lutil_strcopy( ptr, "cn=" );
1885 ptr = lutil_strcopy( ptr, li->li_uri );
1890 return lback->bi_db_open( be );
1893 typedef struct ldap_chain_conn_apply_t {
1896 } ldap_chain_conn_apply_t;
1899 ldap_chain_conn_apply( void *datum, void *arg )
1901 ldapinfo_t *li = (ldapinfo_t *)datum;
1902 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1904 lca->be->be_private = (void *)li;
1906 return lback->bi_connection_destroy( lca->be, lca->conn );
1910 ldap_chain_connection_destroy(
1915 slap_overinst *on = (slap_overinst *) be->bd_info;
1916 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1917 void *private = be->be_private;
1918 ldap_chain_conn_apply_t lca;
1921 be->be_private = NULL;
1924 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1925 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1926 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1927 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1928 be->be_private = private;
1933 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1935 ldap_chain_parse_ctrl(
1945 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1946 rs->sr_text = "Chaining behavior control specified multiple times";
1947 return LDAP_PROTOCOL_ERROR;
1950 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1951 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1952 return LDAP_PROTOCOL_ERROR;
1955 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1956 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1961 /* Parse the control value
1962 * ChainingBehavior ::= SEQUENCE {
1963 * resolveBehavior Behavior OPTIONAL,
1964 * continuationBehavior Behavior OPTIONAL }
1966 * Behavior :: = ENUMERATED {
1967 * chainingPreferred (0),
1968 * chainingRequired (1),
1969 * referralsPreferred (2),
1970 * referralsRequired (3) }
1973 ber = ber_init( &ctrl->ldctl_value );
1975 rs->sr_text = "internal error";
1979 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1980 /* FIXME: since the whole SEQUENCE is optional,
1981 * should we accept no enumerations at all? */
1982 if ( tag != LBER_ENUMERATED ) {
1983 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1984 return LDAP_PROTOCOL_ERROR;
1987 switch ( behavior ) {
1988 case LDAP_CHAINING_PREFERRED:
1989 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1992 case LDAP_CHAINING_REQUIRED:
1993 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1996 case LDAP_REFERRALS_PREFERRED:
1997 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
2000 case LDAP_REFERRALS_REQUIRED:
2001 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2005 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2006 return LDAP_PROTOCOL_ERROR;
2009 tag = ber_peek_tag( ber, &len );
2010 if ( tag == LBER_ENUMERATED ) {
2011 tag = ber_scanf( ber, "e", &behavior );
2012 if ( tag == LBER_ERROR ) {
2013 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
2014 return LDAP_PROTOCOL_ERROR;
2018 if ( tag == LBER_DEFAULT ) {
2019 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2022 switch ( behavior ) {
2023 case LDAP_CHAINING_PREFERRED:
2024 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2027 case LDAP_CHAINING_REQUIRED:
2028 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2031 case LDAP_REFERRALS_PREFERRED:
2032 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2035 case LDAP_REFERRALS_REQUIRED:
2036 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2040 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2041 return LDAP_PROTOCOL_ERROR;
2045 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2046 rs->sr_text = "Chaining behavior control: decoding error";
2047 return LDAP_PROTOCOL_ERROR;
2050 (void) ber_free( ber, 1 );
2053 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2054 ? SLAP_CONTROL_CRITICAL
2055 : SLAP_CONTROL_NONCRITICAL );
2057 return LDAP_SUCCESS;
2059 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2062 chain_initialize( void )
2066 /* Make sure we don't exceed the bits reserved for userland */
2067 config_check_userland( CH_LAST );
2069 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2070 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2071 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2072 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2073 if ( rc != LDAP_SUCCESS ) {
2074 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2075 "unable to register chaining behavior control: %d.\n",
2079 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2081 ldapchain.on_bi.bi_type = "chain";
2082 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2083 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2084 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2085 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2086 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2088 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2090 ldapchain.on_response = ldap_chain_response;
2092 ldapchain.on_bi.bi_cf_ocs = chainocs;
2094 rc = config_register_schema( chaincfg, chainocs );
2099 return overlay_register( &ldapchain );