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, rs) (lback)->bi_db_destroy( (be), (rs) )
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, NULL);
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, NULL );
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, NULL );
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, NULL );
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://)
841 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
846 matched = rs->sr_matched;
847 rs->sr_matched = NULL;
851 /* we need this to know if back-ldap returned any result */
853 sc2.sc_private = &lb;
854 sc2.sc_response = ldap_chain_cb_response;
855 op->o_callback = &sc2;
857 /* Chaining can be performed by a privileged user on behalf
858 * of normal users, using the ProxyAuthz control, by exploiting
859 * the identity assertion feature of back-ldap; see idassert-*
860 * directives in slapd-ldap(5).
862 * FIXME: the idassert-authcDN is one, will it be fine regardless
863 * of the URI we obtain from the referral?
866 switch ( op->o_tag ) {
867 case LDAP_REQ_BIND: {
868 struct berval rndn = op->o_req_ndn;
869 Connection *conn = op->o_conn;
871 /* FIXME: can we really get a referral for binds? */
872 op->o_req_ndn = slap_empty_bv;
874 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
875 op->o_req_ndn = rndn;
881 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
884 case LDAP_REQ_DELETE:
885 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
888 case LDAP_REQ_MODRDN:
889 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
892 case LDAP_REQ_MODIFY:
893 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
896 case LDAP_REQ_COMPARE:
897 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
898 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
903 case LDAP_REQ_SEARCH:
904 if ( rs->sr_type == REP_SEARCHREF ) {
905 rc = ldap_chain_search( op, rs, ref, 0 );
908 /* we might get here before any database actually
909 * performed a search; in those cases, we need
910 * to check limits, to make sure safe defaults
912 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
913 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
916 rc = SLAP_CB_CONTINUE;
921 case LDAP_REQ_EXTENDED:
922 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
923 /* FIXME: ldap_back_extended() by design
924 * doesn't send result; frontend is expected
926 /* FIXME: what about chaining? */
927 if ( rc != SLAPD_ABANDON ) {
929 send_ldap_extended( op, rs );
932 lb.lb_status = LDAP_CH_RES;
936 rc = SLAP_CB_CONTINUE;
946 /* slapd-ldap sent response */
947 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
948 /* FIXME: should we send response? */
949 Debug( LDAP_DEBUG_ANY,
950 "%s: ldap_chain_response: "
951 "overlay should have sent result.\n",
952 op->o_log_prefix, 0, 0 );
957 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
958 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
962 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
963 case LDAP_CHAINING_REQUIRED:
965 op->o_callback = NULL;
966 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
967 "operation cannot be completed without chaining" );
971 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
972 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
974 rs->sr_type = sr_type;
977 rc = SLAP_CB_CONTINUE;
979 rs->sr_type = sr_type;
981 rs->sr_matched = matched;
984 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
987 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
990 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
991 op->o_callback = NULL;
992 rc = rs->sr_err = slap_map_api2result( rs );
993 send_ldap_result( op, rs );
998 rs->sr_type = sr_type;
1000 rs->sr_matched = matched;
1003 op->o_callback = sc;
1009 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1011 ldap_chain_parse_ctrl(
1014 LDAPControl *ctrl );
1017 str2chain( const char *s )
1019 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1020 return LDAP_CHAINING_PREFERRED;
1022 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1023 return LDAP_CHAINING_REQUIRED;
1025 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1026 return LDAP_REFERRALS_PREFERRED;
1028 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1029 return LDAP_REFERRALS_REQUIRED;
1034 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1049 static ConfigDriver chain_cf_gen;
1050 static ConfigCfAdd chain_cfadd;
1051 static ConfigLDAPadd chain_ldadd;
1053 static ConfigTable chaincfg[] = {
1054 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1055 { "chain-chaining", "args",
1056 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1057 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1058 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1059 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1060 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1061 { "chain-cache-uri", "TRUE/FALSE",
1062 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1063 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1064 "DESC 'Enables caching of URIs not present in configuration' "
1065 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1066 { "chain-max-depth", "args",
1067 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1068 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1069 "DESC 'max referral depth' "
1070 "SYNTAX OMsInteger "
1071 "EQUALITY integerMatch "
1072 "SINGLE-VALUE )", NULL, NULL },
1073 { "chain-return-error", "TRUE/FALSE",
1074 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1075 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1076 "DESC 'Errors are returned instead of the original referral' "
1077 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1078 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1081 static ConfigOCs chainocs[] = {
1082 { "( OLcfgOvOc:3.1 "
1083 "NAME 'olcChainConfig' "
1084 "DESC 'Chain configuration' "
1085 "SUP olcOverlayConfig "
1087 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1088 "olcChainingBehavior $ "
1089 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1090 "olcChainCacheURI $ "
1091 "olcChainMaxReferralDepth $ "
1092 "olcChainReturnError "
1094 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1095 { "( OLcfgOvOc:3.2 "
1096 "NAME 'olcChainDatabase' "
1097 "DESC 'Chain remote server configuration' "
1099 Cft_Misc, chaincfg, chain_ldadd },
1104 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1111 AttributeDescription *ad = NULL;
1117 if ( p->ce_type != Cft_Overlay
1119 || p->ce_bi->bi_cf_ocs != chainocs )
1121 return LDAP_CONSTRAINT_VIOLATION;
1124 on = (slap_overinst *)p->ce_bi;
1125 lc = (ldap_chain_t *)on->on_bi.bi_private;
1127 assert( ca->be == NULL );
1128 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1130 ca->be->bd_info = (BackendInfo *)on;
1132 rc = slap_str2ad( "olcDbURI", &ad, &text );
1133 assert( rc == LDAP_SUCCESS );
1135 at = attr_find( e->e_attrs, ad );
1136 if ( lc->lc_common_li == NULL && at != NULL ) {
1137 /* FIXME: we should generate an empty default entry
1138 * if none is supplied */
1139 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1140 "first underlying database \"%s\" "
1141 "cannot contain attribute \"%s\".\n",
1142 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1143 rc = LDAP_CONSTRAINT_VIOLATION;
1146 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1147 /* FIXME: we should generate an empty default entry
1148 * if none is supplied */
1149 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1150 "subsequent underlying database \"%s\" "
1151 "must contain attribute \"%s\".\n",
1152 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1153 rc = LDAP_CONSTRAINT_VIOLATION;
1157 if ( lc->lc_common_li == NULL ) {
1158 rc = ldap_chain_db_init_common( ca->be );
1161 rc = ldap_chain_db_init_one( ca->be );
1165 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1166 "unable to init %sunderlying database \"%s\".\n",
1167 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1168 return LDAP_CONSTRAINT_VIOLATION;
1171 li = ca->be->be_private;
1173 if ( lc->lc_common_li == NULL ) {
1174 lc->lc_common_li = li;
1177 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1178 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1179 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1180 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1182 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1183 "database \"%s\" insert failed.\n",
1184 e->e_name.bv_val, 0, 0 );
1185 rc = LDAP_CONSTRAINT_VIOLATION;
1191 if ( rc != LDAP_SUCCESS ) {
1192 (void)ldap_chain_db_destroy_one( ca->be, NULL );
1200 typedef struct ldap_chain_cfadd_apply_t {
1206 } ldap_chain_cfadd_apply_t;
1209 ldap_chain_cfadd_apply( void *datum, void *arg )
1211 ldapinfo_t *li = (ldapinfo_t *)datum;
1212 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1216 /* FIXME: should not hardcode "olcDatabase" here */
1217 bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
1218 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1219 bv.bv_val = lca->ca->cr_msg;
1221 lca->ca->be->be_private = (void *)li;
1222 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1223 &bv, lback->bi_cf_ocs, &chainocs[1] );
1231 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1233 CfEntryInfo *pe = p->e_private;
1234 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1235 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1236 void *priv = (void *)ca->be->be_private;
1238 if ( lback->bi_cf_ocs ) {
1239 ldap_chain_cfadd_apply_t lca = { 0 };
1247 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1249 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1250 &lca, 1, AVL_INORDER );
1252 ca->be->be_private = priv;
1258 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1259 static slap_verbmasks chaining_mode[] = {
1260 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1261 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1262 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1263 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1266 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1269 chain_cf_gen( ConfigArgs *c )
1271 slap_overinst *on = (slap_overinst *)c->bi;
1272 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1276 if ( c->op == SLAP_CONFIG_EMIT ) {
1278 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1280 struct berval resolve = BER_BVNULL,
1281 continuation = BER_BVNULL;
1283 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1287 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1288 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1290 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1292 + STRLENOF( "continuation=" ) + continuation.bv_len;
1293 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1294 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1295 "resolve=%s continuation=%s",
1296 resolve.bv_val, continuation.bv_val );
1298 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1299 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1300 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1301 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1302 " critical", STRLENOF( " critical" ) + 1 );
1303 c->value_bv.bv_len += STRLENOF( " critical" );
1308 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1311 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1315 c->value_int = lc->lc_max_depth;
1319 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1328 } else if ( c->op == LDAP_MOD_DELETE ) {
1334 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1342 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1353 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1354 char **argv = c->argv;
1356 BerElementBuffer berbuf;
1357 BerElement *ber = (BerElement *)&berbuf;
1361 Operation op = { 0 };
1362 SlapReply rs = { 0 };
1364 lc->lc_chaining_ctrlflag = 0;
1366 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1367 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1368 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1369 if ( resolve == -1 ) {
1370 Debug( LDAP_DEBUG_ANY, "%s: "
1371 "illegal <resolve> value %s "
1372 "in \"chain-chaining>\".\n",
1373 c->log, argv[ 0 ], 0 );
1377 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1378 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1379 if ( continuation == -1 ) {
1380 Debug( LDAP_DEBUG_ANY, "%s: "
1381 "illegal <continuation> value %s "
1382 "in \"chain-chaining\".\n",
1383 c->log, argv[ 0 ], 0 );
1387 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1391 Debug( LDAP_DEBUG_ANY, "%s: "
1392 "unknown option in \"chain-chaining\".\n",
1398 if ( resolve != -1 || continuation != -1 ) {
1401 if ( resolve == -1 ) {
1403 resolve = SLAP_CHAINING_DEFAULT;
1406 ber_init2( ber, NULL, LBER_USE_DER );
1408 err = ber_printf( ber, "{e" /* } */, resolve );
1411 Debug( LDAP_DEBUG_ANY, "%s: "
1412 "chaining behavior control encoding error!\n",
1417 if ( continuation > -1 ) {
1418 err = ber_printf( ber, "e", continuation );
1421 Debug( LDAP_DEBUG_ANY, "%s: "
1422 "chaining behavior control encoding error!\n",
1428 err = ber_printf( ber, /* { */ "N}" );
1431 Debug( LDAP_DEBUG_ANY, "%s: "
1432 "chaining behavior control encoding error!\n",
1437 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1438 exit( EXIT_FAILURE );
1442 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1445 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1446 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1448 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1450 Debug( LDAP_DEBUG_ANY, "%s: "
1451 "unable to parse chaining control%s%s.\n",
1452 c->log, rs.sr_text ? ": " : "",
1453 rs.sr_text ? rs.sr_text : "" );
1457 lc->lc_chaining_ctrlflag = op.o_chaining;
1459 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1462 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1463 Debug( LDAP_DEBUG_ANY, "%s: "
1464 "\"chaining\" control unsupported (ignored).\n",
1466 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1470 if ( c->value_int ) {
1471 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1473 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1478 if ( c->value_int < 0 ) {
1479 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1480 "<%s> invalid max referral depth %d",
1481 c->argv[0], c->value_int );
1482 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1483 c->log, c->cr_msg, 0 );
1487 lc->lc_max_depth = c->value_int;
1490 if ( c->value_int ) {
1491 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1493 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1509 slap_overinst *on = (slap_overinst *)be->bd_info;
1510 ldap_chain_t *lc = NULL;
1512 if ( lback == NULL ) {
1513 static BackendInfo lback2;
1515 lback = backend_info( "ldap" );
1517 if ( lback == NULL ) {
1522 lback2.bi_type = ldapchain.on_bi.bi_type;
1526 lc = ch_malloc( sizeof( ldap_chain_t ) );
1530 memset( lc, 0, sizeof( ldap_chain_t ) );
1531 lc->lc_max_depth = 1;
1532 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1534 on->on_bi.bi_private = (void *)lc;
1540 ldap_chain_db_config(
1547 slap_overinst *on = (slap_overinst *)be->bd_info;
1548 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1550 int rc = SLAP_CONF_UNKNOWN;
1552 if ( lc->lc_common_li == NULL ) {
1553 void *be_private = be->be_private;
1554 ldap_chain_db_init_common( be );
1555 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1556 be->be_private = be_private;
1559 /* Something for the chain database? */
1560 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1561 char *save_argv0 = argv[ 0 ];
1562 BackendInfo *bd_info = be->bd_info;
1563 void *be_private = be->be_private;
1564 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1565 static char *allowed_argv[] = {
1566 /* special: put URI here, so in the meanwhile
1567 * it detects whether a new URI is being provided */
1573 /* FIXME: maybe rebind-as-user should be allowed
1574 * only within known URIs... */
1581 int which_argv = -1;
1583 argv[ 0 ] += STRLENOF( "chain-" );
1585 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1586 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1591 if ( allowed_argv[ which_argv ] == NULL ) {
1594 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1595 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1596 "\"%s\" only allowed within a URI directive.\n.",
1597 fname, lineno, argv[ 0 ] );
1602 if ( which_argv == 0 ) {
1603 rc = ldap_chain_db_init_one( be );
1605 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1606 "underlying slapd-ldap initialization failed.\n.",
1610 lc->lc_cfg_li = be->be_private;
1613 /* TODO: add checks on what other slapd-ldap(5) args
1614 * should be put in the template; this is not quite
1615 * harmful, because attributes that shouldn't don't
1616 * get actually used, but the user should at least
1620 be->bd_info = lback;
1621 be->be_private = (void *)lc->lc_cfg_li;
1622 be->be_cf_ocs = lback->bi_cf_ocs;
1624 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1626 argv[ 0 ] = save_argv0;
1627 be->be_cf_ocs = be_cf_ocs;
1628 be->be_private = be_private;
1629 be->bd_info = bd_info;
1631 if ( which_argv == 0 ) {
1637 db.be_private = (void *)lc->lc_cfg_li;
1638 ldap_chain_db_destroy_one( &db, NULL );
1639 lc->lc_cfg_li = NULL;
1642 if ( lc->lc_cfg_li->li_bvuri == NULL
1643 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1644 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1646 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1647 "no URI list allowed in slapo-chain.\n",
1650 goto private_destroy;
1653 if ( avl_insert( &lc->lc_lai.lai_tree,
1654 (caddr_t)lc->lc_cfg_li,
1655 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1657 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1658 "duplicate URI in slapo-chain.\n",
1661 goto private_destroy;
1678 typedef struct ldap_chain_db_apply_t {
1681 } ldap_chain_db_apply_t;
1684 ldap_chain_db_apply( void *datum, void *arg )
1686 ldapinfo_t *li = (ldapinfo_t *)datum;
1687 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1689 lca->be->be_private = (void *)li;
1691 return lca->func( lca->be, NULL );
1700 slap_overinst *on = (slap_overinst *)be->bd_info;
1701 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1706 BI_db_func *func = (&lback->bi_db_open)[ which ];
1708 if ( func != NULL && lc->lc_common_li != NULL ) {
1712 db.be_private = lc->lc_common_li;
1714 rc = func( &db, NULL );
1720 if ( lc->lc_lai.lai_tree != NULL ) {
1721 ldap_chain_db_apply_t lca;
1726 rc = avl_apply( lc->lc_lai.lai_tree,
1727 ldap_chain_db_apply, (void *)&lca,
1728 1, AVL_INORDER ) != AVL_NOMORE;
1741 slap_overinst *on = (slap_overinst *) be->bd_info;
1742 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1743 slap_mask_t monitoring;
1746 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1747 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1751 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1753 if ( lc->lc_common_li == NULL ) {
1754 void *be_private = be->be_private;
1755 ldap_chain_db_init_common( be );
1756 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1757 be->be_private = be_private;
1760 /* filter out and restore monitoring */
1761 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1762 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1763 rc = ldap_chain_db_func( be, db_open );
1764 SLAP_DBFLAGS( be ) |= monitoring;
1770 ldap_chain_db_close(
1774 return ldap_chain_db_func( be, db_close );
1778 ldap_chain_db_destroy(
1782 slap_overinst *on = (slap_overinst *) be->bd_info;
1783 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1787 rc = ldap_chain_db_func( be, db_destroy );
1790 avl_free( lc->lc_lai.lai_tree, NULL );
1791 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1799 * inits one instance of the slapd-ldap backend, and stores
1800 * the private info in be_private of the arg
1803 ldap_chain_db_init_common(
1806 BackendInfo *bi = be->bd_info;
1810 be->bd_info = lback;
1811 be->be_private = NULL;
1812 rc = lback->bi_db_init( be, NULL );
1816 li = (ldapinfo_t *)be->be_private;
1817 li->li_urllist_f = NULL;
1818 li->li_urllist_p = NULL;
1826 * inits one instance of the slapd-ldap backend, stores
1827 * the private info in be_private of the arg and fills
1828 * selected fields with data from the template.
1830 * NOTE: add checks about the other fields of the template,
1831 * which are ignored and SHOULD NOT be configured by the user.
1834 ldap_chain_db_init_one(
1837 slap_overinst *on = (slap_overinst *)be->bd_info;
1838 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1840 BackendInfo *bi = be->bd_info;
1845 be->bd_info = lback;
1846 be->be_private = NULL;
1847 t = lback->bi_db_init( be, NULL );
1851 li = (ldapinfo_t *)be->be_private;
1852 li->li_urllist_f = NULL;
1853 li->li_urllist_p = NULL;
1855 /* copy common data */
1856 li->li_nretries = lc->lc_common_li->li_nretries;
1857 li->li_flags = lc->lc_common_li->li_flags;
1858 li->li_version = lc->lc_common_li->li_version;
1859 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1860 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1868 ldap_chain_db_open_one(
1871 if ( SLAP_DBMONITORING( be ) ) {
1872 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1874 if ( li->li_uri == NULL ) {
1875 ber_str2bv( "cn=Common Connections", 0, 1,
1876 &li->li_monitor_info.lmi_rdn );
1881 li->li_monitor_info.lmi_rdn.bv_len
1882 = STRLENOF( "cn=" ) + strlen( li->li_uri );
1883 ptr = li->li_monitor_info.lmi_rdn.bv_val
1884 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
1885 ptr = lutil_strcopy( ptr, "cn=" );
1886 ptr = lutil_strcopy( ptr, li->li_uri );
1891 return lback->bi_db_open( be, NULL );
1894 typedef struct ldap_chain_conn_apply_t {
1897 } ldap_chain_conn_apply_t;
1900 ldap_chain_conn_apply( void *datum, void *arg )
1902 ldapinfo_t *li = (ldapinfo_t *)datum;
1903 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1905 lca->be->be_private = (void *)li;
1907 return lback->bi_connection_destroy( lca->be, lca->conn );
1911 ldap_chain_connection_destroy(
1916 slap_overinst *on = (slap_overinst *) be->bd_info;
1917 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1918 void *private = be->be_private;
1919 ldap_chain_conn_apply_t lca;
1922 be->be_private = NULL;
1925 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1926 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1927 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1928 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1929 be->be_private = private;
1934 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1936 ldap_chain_parse_ctrl(
1946 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1947 rs->sr_text = "Chaining behavior control specified multiple times";
1948 return LDAP_PROTOCOL_ERROR;
1951 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1952 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1953 return LDAP_PROTOCOL_ERROR;
1956 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1957 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1962 /* Parse the control value
1963 * ChainingBehavior ::= SEQUENCE {
1964 * resolveBehavior Behavior OPTIONAL,
1965 * continuationBehavior Behavior OPTIONAL }
1967 * Behavior :: = ENUMERATED {
1968 * chainingPreferred (0),
1969 * chainingRequired (1),
1970 * referralsPreferred (2),
1971 * referralsRequired (3) }
1974 ber = ber_init( &ctrl->ldctl_value );
1976 rs->sr_text = "internal error";
1980 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1981 /* FIXME: since the whole SEQUENCE is optional,
1982 * should we accept no enumerations at all? */
1983 if ( tag != LBER_ENUMERATED ) {
1984 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1985 return LDAP_PROTOCOL_ERROR;
1988 switch ( behavior ) {
1989 case LDAP_CHAINING_PREFERRED:
1990 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1993 case LDAP_CHAINING_REQUIRED:
1994 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1997 case LDAP_REFERRALS_PREFERRED:
1998 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
2001 case LDAP_REFERRALS_REQUIRED:
2002 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2006 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2007 return LDAP_PROTOCOL_ERROR;
2010 tag = ber_peek_tag( ber, &len );
2011 if ( tag == LBER_ENUMERATED ) {
2012 tag = ber_scanf( ber, "e", &behavior );
2013 if ( tag == LBER_ERROR ) {
2014 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
2015 return LDAP_PROTOCOL_ERROR;
2019 if ( tag == LBER_DEFAULT ) {
2020 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2023 switch ( behavior ) {
2024 case LDAP_CHAINING_PREFERRED:
2025 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2028 case LDAP_CHAINING_REQUIRED:
2029 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2032 case LDAP_REFERRALS_PREFERRED:
2033 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2036 case LDAP_REFERRALS_REQUIRED:
2037 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2041 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2042 return LDAP_PROTOCOL_ERROR;
2046 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2047 rs->sr_text = "Chaining behavior control: decoding error";
2048 return LDAP_PROTOCOL_ERROR;
2051 (void) ber_free( ber, 1 );
2054 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2055 ? SLAP_CONTROL_CRITICAL
2056 : SLAP_CONTROL_NONCRITICAL );
2058 return LDAP_SUCCESS;
2060 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2063 chain_initialize( void )
2067 /* Make sure we don't exceed the bits reserved for userland */
2068 config_check_userland( CH_LAST );
2070 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2071 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2072 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2073 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2074 if ( rc != LDAP_SUCCESS ) {
2075 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2076 "unable to register chaining behavior control: %d.\n",
2080 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2082 ldapchain.on_bi.bi_type = "chain";
2083 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2084 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2085 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2086 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2087 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2089 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2091 ldapchain.on_response = ldap_chain_response;
2093 ldapchain.on_bi.bi_cf_ocs = chainocs;
2095 rc = config_register_schema( chaincfg, chainocs );
2100 return overlay_register( &ldapchain );