1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2010 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;
67 static BackendInfo *lback;
69 typedef struct ldap_chain_t {
71 * A "template" ldapinfo_t gets all common configuration items;
72 * then, for each configured URI, an entry is created in the tree;
73 * all the specific configuration items get in the current URI
76 * Then, for each referral, extract the URI and lookup the
77 * related structure. If configured to do so, allow URIs
78 * not found in the structure to create a temporary one
79 * that chains anonymously; maybe it can also be added to
80 * the tree? Should be all configurable.
83 /* "common" configuration info (anything occurring before an "uri") */
84 ldapinfo_t *lc_common_li;
86 /* current configuration info */
87 ldapinfo_t *lc_cfg_li;
89 /* tree of configured[/generated?] "uri" info */
90 ldap_avl_info_t lc_lai;
92 /* max depth in nested referrals chaining */
96 #define LDAP_CHAIN_F_NONE (0x00U)
97 #define LDAP_CHAIN_F_CHAINING (0x01U)
98 #define LDAP_CHAIN_F_CACHE_URI (0x02U)
99 #define LDAP_CHAIN_F_RETURN_ERR (0x04U)
101 #define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
102 #define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
103 #define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
104 #define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
106 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
107 LDAPControl lc_chaining_ctrl;
108 char lc_chaining_ctrlflag;
109 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
112 static int ldap_chain_db_init_common( BackendDB *be );
113 static int ldap_chain_db_init_one( BackendDB *be );
114 static int ldap_chain_db_open_one( BackendDB *be );
115 #define ldap_chain_db_close_one(be) (0)
116 #define ldap_chain_db_destroy_one(be, rs) (lback)->bi_db_destroy( (be), (rs) )
118 typedef struct ldap_chain_cb_t {
119 ldap_chain_status_t lb_status;
140 static slap_overinst ldapchain;
142 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
144 chaining_control_add(
147 LDAPControl ***oldctrlsp )
149 LDAPControl **ctrls = NULL;
152 *oldctrlsp = op->o_ctrls;
154 /* default chaining control not defined */
155 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
159 /* already present */
160 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
164 /* FIXME: check other incompatibilities */
166 /* add to other controls */
168 for ( c = 0; op->o_ctrls[ c ]; c++ )
172 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
173 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
175 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
176 ctrls[ c + 1 ] = op->o_ctrls[ c ];
179 ctrls[ c + 1 ] = NULL;
183 op->o_chaining = lc->lc_chaining_ctrlflag;
189 chaining_control_remove(
191 LDAPControl ***oldctrlsp )
193 LDAPControl **oldctrls = *oldctrlsp;
195 /* we assume that the first control is the chaining control
196 * added by the chain overlay, so it's the only one we explicitly
198 if ( op->o_ctrls != oldctrls ) {
199 assert( op->o_ctrls != NULL );
200 assert( op->o_ctrls[ 0 ] != NULL );
205 op->o_ctrls = oldctrls;
212 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
215 ldap_chain_uri_cmp( const void *c1, const void *c2 )
217 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
218 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
220 assert( li1->li_bvuri != NULL );
221 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
222 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
224 assert( li2->li_bvuri != NULL );
225 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
226 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
228 /* If local DNs don't match, it is definitely not a match */
229 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
233 ldap_chain_uri_dup( void *c1, void *c2 )
235 ldapinfo_t *li1 = (ldapinfo_t *)c1;
236 ldapinfo_t *li2 = (ldapinfo_t *)c2;
238 assert( li1->li_bvuri != NULL );
239 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
240 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
242 assert( li2->li_bvuri != NULL );
243 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
244 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
246 /* Cannot have more than one shared session with same DN */
247 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
255 * Search specific response that strips entryDN from entries
258 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
260 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
262 assert( op->o_tag == LDAP_REQ_SEARCH );
264 /* if in error, don't proceed any further */
265 if ( lb->lb_status == LDAP_CH_ERR ) {
269 if ( rs->sr_type == REP_SEARCH ) {
270 Attribute **ap = &rs->sr_entry->e_attrs;
272 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
273 /* will be generated later by frontend
274 * (a cleaner solution would be that
275 * the frontend checks if it already exists */
276 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
283 /* there SHOULD be one only! */
288 /* tell the frontend not to add generated
289 * operational attributes */
290 rs->sr_flags |= REP_NO_OPERATIONALS;
292 return SLAP_CB_CONTINUE;
294 } else if ( rs->sr_type == REP_SEARCHREF ) {
295 /* if we get it here, it means the library was unable
296 * to chase the referral... */
297 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
298 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
301 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
302 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
303 switch ( get_continuationBehavior( op ) ) {
304 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
305 lb->lb_status = LDAP_CH_ERR;
306 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
312 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
313 return SLAP_CB_CONTINUE;
315 } else if ( rs->sr_type == REP_RESULT ) {
316 if ( rs->sr_err == LDAP_REFERRAL
317 && lb->lb_depth < lb->lb_lc->lc_max_depth
318 && rs->sr_ref != NULL )
320 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
323 /* back-ldap tried to send result */
324 lb->lb_status = LDAP_CH_RES;
331 * Dummy response that simply traces if back-ldap tried to send
332 * anything to the client
335 ldap_chain_cb_response( Operation *op, SlapReply *rs )
337 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
339 /* if in error, don't proceed any further */
340 if ( lb->lb_status == LDAP_CH_ERR ) {
344 if ( rs->sr_type == REP_RESULT ) {
346 switch ( rs->sr_err ) {
347 case LDAP_COMPARE_TRUE:
348 case LDAP_COMPARE_FALSE:
349 if ( op->o_tag != LDAP_REQ_COMPARE ) {
355 lb->lb_status = LDAP_CH_RES;
359 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
360 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
364 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
365 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
366 switch ( get_continuationBehavior( op ) ) {
367 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
368 lb->lb_status = LDAP_CH_ERR;
369 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
375 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
382 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
384 /* strip the entryDN attribute, but keep returning results */
385 (void)ldap_chain_cb_search_response( op, rs );
388 return SLAP_CB_CONTINUE;
399 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
400 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
401 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
402 ldapinfo_t li = { 0 }, *lip = NULL;
403 struct berval bvuri[ 2 ] = { { 0 } };
405 /* NOTE: returned if ref is empty... */
409 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
410 LDAPControl **ctrls = NULL;
412 (void)chaining_control_add( lc, op, &ctrls );
413 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
417 for ( ; !BER_BVISNULL( ref ); ref++ ) {
418 SlapReply rs2 = { 0 };
419 LDAPURLDesc *srv = NULL;
420 struct berval save_req_dn = op->o_req_dn,
421 save_req_ndn = op->o_req_ndn,
427 /* We're setting the URI of the first referral;
428 * what if there are more?
434 If the client wishes to progress the operation, it MUST follow the
435 referral by contacting one of the supported services. If multiple
436 URIs are present, the client assumes that any supported URI may be
437 used to progress the operation.
439 * so we actually need to follow exactly one,
440 * and we can assume any is fine.
443 /* parse reference and use
444 * proto://[host][:port]/ only */
445 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
446 if ( rc != LDAP_URL_SUCCESS ) {
454 srv->lud_scope = LDAP_SCOPE_DEFAULT;
455 if ( srv->lud_dn != NULL ) {
456 ber_str2bv( srv->lud_dn, 0, 0, &dn );
457 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
458 if ( rc == LDAP_SUCCESS ) {
459 /* remove DN essentially because later on
460 * ldap_initialize() will parse the URL
461 * as a comma-separated URL list */
469 li.li_uri = ldap_url_desc2str( srv );
470 srv->lud_dn = dn.bv_val;
471 ldap_free_urldesc( srv );
473 if ( rc != LDAP_SUCCESS ) {
479 if ( li.li_uri == NULL ) {
482 goto further_cleanup;
488 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
490 /* Searches for a ldapinfo in the avl tree */
491 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
492 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
493 (caddr_t)&li, ldap_chain_uri_cmp );
494 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
497 op->o_bd->be_private = (void *)lip;
500 rc = ldap_chain_db_init_one( op->o_bd );
504 lip = (ldapinfo_t *)op->o_bd->be_private;
505 lip->li_uri = li.li_uri;
506 lip->li_bvuri = bvuri;
507 rc = ldap_chain_db_open_one( op->o_bd );
510 lip->li_bvuri = NULL;
511 (void)ldap_chain_db_destroy_one( op->o_bd, NULL);
515 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
516 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
517 if ( avl_insert( &lc->lc_lai.lai_tree,
518 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
520 /* someone just inserted another;
521 * don't bother, use this and then
525 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
533 lb->lb_depth = depth + 1;
535 rc = op_f( op, &rs2 );
537 /* note the first error */
538 if ( first_rc == -1 ) {
543 ldap_memfree( li.li_uri );
548 lip->li_bvuri = NULL;
549 (void)ldap_chain_db_close_one( op->o_bd );
550 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
554 if ( !BER_BVISNULL( &pdn ) ) {
555 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
557 op->o_req_dn = save_req_dn;
559 if ( !BER_BVISNULL( &ndn ) ) {
560 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
562 op->o_req_ndn = save_req_ndn;
564 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
572 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
573 (void)chaining_control_remove( op, &ctrls );
574 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
576 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
591 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
592 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
593 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
594 ldapinfo_t li = { 0 }, *lip = NULL;
595 struct berval bvuri[ 2 ] = { { 0 } };
597 struct berval odn = op->o_req_dn,
598 ondn = op->o_req_ndn;
599 slap_response *save_response = op->o_callback->sc_response;
600 Entry *save_entry = rs->sr_entry;
601 slap_mask_t save_flags = rs->sr_flags;
606 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
607 LDAPControl **ctrls = NULL;
609 (void)chaining_control_add( lc, op, &ctrls );
610 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
612 rs->sr_type = REP_SEARCH;
614 op->o_callback->sc_response = ldap_chain_cb_search_response;
616 /* if we parse the URI then by no means
617 * we can cache stuff or reuse connections,
618 * because in back-ldap there's no caching
619 * based on the URI value, which is supposed
620 * to be set once for all (correct?) */
622 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
623 SlapReply rs2 = { 0 };
625 struct berval save_req_dn = op->o_req_dn,
626 save_req_ndn = op->o_req_ndn,
632 /* parse reference and use
633 * proto://[host][:port]/ only */
634 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
635 if ( rc != LDAP_URL_SUCCESS ) {
637 rs->sr_err = LDAP_OTHER;
642 rc = LDAP_INVALID_SYNTAX;
643 if ( srv->lud_dn != NULL ) {
644 ber_str2bv( srv->lud_dn, 0, 0, &dn );
645 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
646 if ( rc == LDAP_SUCCESS ) {
647 /* remove DN essentially because later on
648 * ldap_initialize() will parse the URL
649 * as a comma-separated URL list */
651 srv->lud_scope = LDAP_SCOPE_DEFAULT;
652 li.li_uri = ldap_url_desc2str( srv );
653 srv->lud_dn = dn.bv_val;
656 ldap_free_urldesc( srv );
658 if ( rc != LDAP_SUCCESS ) {
664 if ( li.li_uri == NULL ) {
667 goto further_cleanup;
673 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
675 /* Searches for a ldapinfo in the avl tree */
676 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
677 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
678 (caddr_t)&li, ldap_chain_uri_cmp );
679 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
682 op->o_bd->be_private = (void *)lip;
685 /* if none is found, create a temporary... */
686 rc = ldap_chain_db_init_one( op->o_bd );
690 lip = (ldapinfo_t *)op->o_bd->be_private;
691 lip->li_uri = li.li_uri;
692 lip->li_bvuri = bvuri;
693 rc = ldap_chain_db_open_one( op->o_bd );
696 lip->li_bvuri = NULL;
697 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
701 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
702 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
703 if ( avl_insert( &lc->lc_lai.lai_tree,
704 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
706 /* someone just inserted another;
707 * don't bother, use this and then
711 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
718 lb->lb_op_f = lback->bi_op_search;
719 lb->lb_depth = depth + 1;
721 /* FIXME: should we also copy filter and scope?
722 * according to RFC3296, no */
723 rc = lback->bi_op_search( op, &rs2 );
724 if ( first_rc == -1 ) {
729 ldap_memfree( li.li_uri );
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, NULL );
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;
766 rs->sr_entry = save_entry;
767 rs->sr_flags = save_flags;
769 if ( rc != LDAP_SUCCESS ) {
770 /* couldn't chase any of the referrals */
771 if ( first_rc != -1 ) {
775 rc = SLAP_CB_CONTINUE;
783 ldap_chain_response( Operation *op, SlapReply *rs )
785 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
786 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
787 BackendDB db, *bd = op->o_bd;
788 ldap_chain_cb_t lb = { 0 };
789 slap_callback *sc = op->o_callback,
792 const char *text = NULL;
795 struct berval ndn = op->o_ndn;
797 int sr_err = rs->sr_err;
798 slap_reply_t sr_type = rs->sr_type;
799 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
800 slap_mask_t chain_mask = 0;
801 ber_len_t chain_shift = 0;
802 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
804 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
805 return SLAP_CB_CONTINUE;
808 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
809 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
810 switch ( get_resolveBehavior( op ) ) {
811 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
812 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
813 return SLAP_CB_CONTINUE;
816 chain_mask = SLAP_CH_RESOLVE_MASK;
817 chain_shift = SLAP_CH_RESOLVE_SHIFT;
821 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
822 switch ( get_continuationBehavior( op ) ) {
823 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
824 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
825 return SLAP_CB_CONTINUE;
828 chain_mask = SLAP_CH_CONTINUATION_MASK;
829 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
833 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
836 * TODO: add checks on who/when chain operations; e.g.:
837 * a) what identities are authorized
838 * b) what request DN (e.g. only chain requests rooted at <DN>)
839 * c) what referral URIs
840 * d) what protocol scheme (e.g. only ldaps://)
845 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
850 matched = rs->sr_matched;
851 rs->sr_matched = NULL;
855 /* we need this to know if back-ldap returned any result */
857 sc2.sc_next = sc->sc_next;
858 sc2.sc_private = &lb;
859 sc2.sc_response = ldap_chain_cb_response;
860 op->o_callback = &sc2;
862 /* Chaining can be performed by a privileged user on behalf
863 * of normal users, using the ProxyAuthz control, by exploiting
864 * the identity assertion feature of back-ldap; see idassert-*
865 * directives in slapd-ldap(5).
867 * FIXME: the idassert-authcDN is one, will it be fine regardless
868 * of the URI we obtain from the referral?
871 switch ( op->o_tag ) {
872 case LDAP_REQ_BIND: {
873 struct berval rndn = op->o_req_ndn;
874 Connection *conn = op->o_conn;
876 /* FIXME: can we really get a referral for binds? */
877 op->o_req_ndn = slap_empty_bv;
879 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
880 op->o_req_ndn = rndn;
886 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
889 case LDAP_REQ_DELETE:
890 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
893 case LDAP_REQ_MODRDN:
894 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
897 case LDAP_REQ_MODIFY:
898 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
901 case LDAP_REQ_COMPARE:
902 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
903 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
908 case LDAP_REQ_SEARCH:
909 if ( rs->sr_type == REP_SEARCHREF ) {
910 rc = ldap_chain_search( op, rs, ref, 0 );
913 /* we might get here before any database actually
914 * performed a search; in those cases, we need
915 * to check limits, to make sure safe defaults
917 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
918 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
921 rc = SLAP_CB_CONTINUE;
926 case LDAP_REQ_EXTENDED:
927 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
928 /* FIXME: ldap_back_extended() by design
929 * doesn't send result; frontend is expected
931 /* FIXME: what about chaining? */
932 if ( rc != SLAPD_ABANDON ) {
934 send_ldap_extended( op, rs );
937 lb.lb_status = LDAP_CH_RES;
941 rc = SLAP_CB_CONTINUE;
952 /* slapd-ldap sent response */
953 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
954 /* FIXME: should we send response? */
955 Debug( LDAP_DEBUG_ANY,
956 "%s: ldap_chain_response: "
957 "overlay should have sent result.\n",
958 op->o_log_prefix, 0, 0 );
963 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
964 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
968 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
969 case LDAP_CHAINING_REQUIRED:
971 op->o_callback = NULL;
972 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
973 "operation cannot be completed without chaining" );
977 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
978 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
979 sr_err = rs->sr_err = rc;
980 rs->sr_type = sr_type;
983 rc = SLAP_CB_CONTINUE;
985 rs->sr_type = sr_type;
987 rs->sr_matched = matched;
990 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
993 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
996 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
997 /* give the remaining callbacks a chance */
998 op->o_callback = sc->sc_next;
999 rc = rs->sr_err = slap_map_api2result( rs );
1000 send_ldap_result( op, rs );
1004 rs->sr_err = sr_err;
1005 rs->sr_type = sr_type;
1007 rs->sr_matched = matched;
1010 op->o_callback = sc;
1016 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1018 ldap_chain_parse_ctrl(
1021 LDAPControl *ctrl );
1024 str2chain( const char *s )
1026 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1027 return LDAP_CHAINING_PREFERRED;
1029 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1030 return LDAP_CHAINING_REQUIRED;
1032 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1033 return LDAP_REFERRALS_PREFERRED;
1035 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1036 return LDAP_REFERRALS_REQUIRED;
1041 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1056 static ConfigDriver chain_cf_gen;
1057 static ConfigCfAdd chain_cfadd;
1058 static ConfigLDAPadd chain_ldadd;
1060 static ConfigTable chaincfg[] = {
1061 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1062 { "chain-chaining", "args",
1063 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1064 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1065 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1066 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1067 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1068 { "chain-cache-uri", "TRUE/FALSE",
1069 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1070 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1071 "DESC 'Enables caching of URIs not present in configuration' "
1072 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1073 { "chain-max-depth", "args",
1074 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1075 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1076 "DESC 'max referral depth' "
1077 "SYNTAX OMsInteger "
1078 "EQUALITY integerMatch "
1079 "SINGLE-VALUE )", NULL, NULL },
1080 { "chain-return-error", "TRUE/FALSE",
1081 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1082 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1083 "DESC 'Errors are returned instead of the original referral' "
1084 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1085 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1088 static ConfigOCs chainocs[] = {
1089 { "( OLcfgOvOc:3.1 "
1090 "NAME 'olcChainConfig' "
1091 "DESC 'Chain configuration' "
1092 "SUP olcOverlayConfig "
1094 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1095 "olcChainingBehavior $ "
1096 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1097 "olcChainCacheURI $ "
1098 "olcChainMaxReferralDepth $ "
1099 "olcChainReturnError "
1101 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1102 { "( OLcfgOvOc:3.2 "
1103 "NAME 'olcChainDatabase' "
1104 "DESC 'Chain remote server configuration' "
1106 Cft_Misc, olcDatabaseDummy, chain_ldadd },
1111 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1118 AttributeDescription *ad = NULL;
1124 if ( p->ce_type != Cft_Overlay
1126 || p->ce_bi->bi_cf_ocs != chainocs )
1128 return LDAP_CONSTRAINT_VIOLATION;
1131 on = (slap_overinst *)p->ce_bi;
1132 lc = (ldap_chain_t *)on->on_bi.bi_private;
1134 assert( ca->be == NULL );
1135 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1137 ca->be->bd_info = (BackendInfo *)on;
1139 rc = slap_str2ad( "olcDbURI", &ad, &text );
1140 assert( rc == LDAP_SUCCESS );
1142 at = attr_find( e->e_attrs, ad );
1143 if ( lc->lc_common_li == NULL && at != NULL ) {
1144 /* FIXME: we should generate an empty default entry
1145 * if none is supplied */
1146 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1147 "first underlying database \"%s\" "
1148 "cannot contain attribute \"%s\".\n",
1149 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1150 rc = LDAP_CONSTRAINT_VIOLATION;
1153 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1154 /* FIXME: we should generate an empty default entry
1155 * if none is supplied */
1156 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1157 "subsequent underlying database \"%s\" "
1158 "must contain attribute \"%s\".\n",
1159 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1160 rc = LDAP_CONSTRAINT_VIOLATION;
1164 if ( lc->lc_common_li == NULL ) {
1165 rc = ldap_chain_db_init_common( ca->be );
1168 rc = ldap_chain_db_init_one( ca->be );
1172 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1173 "unable to init %sunderlying database \"%s\".\n",
1174 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1175 return LDAP_CONSTRAINT_VIOLATION;
1178 li = ca->be->be_private;
1180 if ( lc->lc_common_li == NULL ) {
1181 lc->lc_common_li = li;
1184 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1185 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1186 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1187 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1189 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1190 "database \"%s\" insert failed.\n",
1191 e->e_name.bv_val, 0, 0 );
1192 rc = LDAP_CONSTRAINT_VIOLATION;
1197 ca->ca_private = on;
1200 if ( rc != LDAP_SUCCESS ) {
1201 (void)ldap_chain_db_destroy_one( ca->be, NULL );
1209 typedef struct ldap_chain_cfadd_apply_t {
1215 } ldap_chain_cfadd_apply_t;
1218 ldap_chain_cfadd_apply( void *datum, void *arg )
1220 ldapinfo_t *li = (ldapinfo_t *)datum;
1221 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1225 /* FIXME: should not hardcode "olcDatabase" here */
1226 bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
1227 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1228 bv.bv_val = lca->ca->cr_msg;
1230 lca->ca->be->be_private = (void *)li;
1231 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1232 &bv, lback->bi_cf_ocs, &chainocs[1] );
1240 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1242 CfEntryInfo *pe = p->e_private;
1243 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1244 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1245 void *priv = (void *)ca->be->be_private;
1247 if ( lback->bi_cf_ocs ) {
1248 ldap_chain_cfadd_apply_t lca = { 0 };
1256 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1258 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1259 &lca, 1, AVL_INORDER );
1261 ca->be->be_private = priv;
1267 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1268 static slap_verbmasks chaining_mode[] = {
1269 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1270 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1271 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1272 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1275 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1278 chain_cf_gen( ConfigArgs *c )
1280 slap_overinst *on = (slap_overinst *)c->bi;
1281 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1285 if ( c->op == SLAP_CONFIG_EMIT ) {
1287 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1289 struct berval resolve = BER_BVNULL,
1290 continuation = BER_BVNULL;
1292 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1296 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1297 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1299 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1301 + STRLENOF( "continuation=" ) + continuation.bv_len;
1302 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1303 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1304 "resolve=%s continuation=%s",
1305 resolve.bv_val, continuation.bv_val );
1307 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1308 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1309 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1310 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1311 " critical", STRLENOF( " critical" ) + 1 );
1312 c->value_bv.bv_len += STRLENOF( " critical" );
1317 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1320 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1324 c->value_int = lc->lc_max_depth;
1328 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1337 } else if ( c->op == LDAP_MOD_DELETE ) {
1343 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1351 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1362 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1363 char **argv = c->argv;
1365 BerElementBuffer berbuf;
1366 BerElement *ber = (BerElement *)&berbuf;
1370 Operation op = { 0 };
1371 SlapReply rs = { 0 };
1373 lc->lc_chaining_ctrlflag = 0;
1375 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1376 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1377 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1378 if ( resolve == -1 ) {
1379 Debug( LDAP_DEBUG_ANY, "%s: "
1380 "illegal <resolve> value %s "
1381 "in \"chain-chaining>\".\n",
1382 c->log, argv[ 0 ], 0 );
1386 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1387 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1388 if ( continuation == -1 ) {
1389 Debug( LDAP_DEBUG_ANY, "%s: "
1390 "illegal <continuation> value %s "
1391 "in \"chain-chaining\".\n",
1392 c->log, argv[ 0 ], 0 );
1396 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1400 Debug( LDAP_DEBUG_ANY, "%s: "
1401 "unknown option in \"chain-chaining\".\n",
1407 if ( resolve != -1 || continuation != -1 ) {
1410 if ( resolve == -1 ) {
1412 resolve = SLAP_CHAINING_DEFAULT;
1415 ber_init2( ber, NULL, LBER_USE_DER );
1417 err = ber_printf( ber, "{e" /* } */, resolve );
1420 Debug( LDAP_DEBUG_ANY, "%s: "
1421 "chaining behavior control encoding error!\n",
1426 if ( continuation > -1 ) {
1427 err = ber_printf( ber, "e", continuation );
1430 Debug( LDAP_DEBUG_ANY, "%s: "
1431 "chaining behavior control encoding error!\n",
1437 err = ber_printf( ber, /* { */ "N}" );
1440 Debug( LDAP_DEBUG_ANY, "%s: "
1441 "chaining behavior control encoding error!\n",
1446 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1447 exit( EXIT_FAILURE );
1451 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1454 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1455 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1457 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1459 Debug( LDAP_DEBUG_ANY, "%s: "
1460 "unable to parse chaining control%s%s.\n",
1461 c->log, rs.sr_text ? ": " : "",
1462 rs.sr_text ? rs.sr_text : "" );
1466 lc->lc_chaining_ctrlflag = op.o_chaining;
1468 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1471 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1472 Debug( LDAP_DEBUG_ANY, "%s: "
1473 "\"chaining\" control unsupported (ignored).\n",
1475 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1479 if ( c->value_int ) {
1480 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1482 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1487 if ( c->value_int < 0 ) {
1488 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1489 "<%s> invalid max referral depth %d",
1490 c->argv[0], c->value_int );
1491 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1492 c->log, c->cr_msg, 0 );
1496 lc->lc_max_depth = c->value_int;
1499 if ( c->value_int ) {
1500 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1502 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1518 slap_overinst *on = (slap_overinst *)be->bd_info;
1519 ldap_chain_t *lc = NULL;
1521 if ( lback == NULL ) {
1522 lback = backend_info( "ldap" );
1524 if ( lback == NULL ) {
1529 lc = ch_malloc( sizeof( ldap_chain_t ) );
1533 memset( lc, 0, sizeof( ldap_chain_t ) );
1534 lc->lc_max_depth = 1;
1535 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1537 on->on_bi.bi_private = (void *)lc;
1543 ldap_chain_db_config(
1550 slap_overinst *on = (slap_overinst *)be->bd_info;
1551 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1553 int rc = SLAP_CONF_UNKNOWN;
1555 if ( lc->lc_common_li == NULL ) {
1556 void *be_private = be->be_private;
1557 ldap_chain_db_init_common( be );
1558 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1559 be->be_private = be_private;
1562 /* Something for the chain database? */
1563 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1564 char *save_argv0 = argv[ 0 ];
1565 BackendInfo *bd_info = be->bd_info;
1566 void *be_private = be->be_private;
1567 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1568 static char *allowed_argv[] = {
1569 /* special: put URI here, so in the meanwhile
1570 * it detects whether a new URI is being provided */
1576 /* FIXME: maybe rebind-as-user should be allowed
1577 * only within known URIs... */
1584 int which_argv = -1;
1586 argv[ 0 ] += STRLENOF( "chain-" );
1588 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1589 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1594 if ( allowed_argv[ which_argv ] == NULL ) {
1597 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1598 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1599 "\"%s\" only allowed within a URI directive.\n.",
1600 fname, lineno, argv[ 0 ] );
1605 if ( which_argv == 0 ) {
1606 rc = ldap_chain_db_init_one( be );
1608 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1609 "underlying slapd-ldap initialization failed.\n.",
1613 lc->lc_cfg_li = be->be_private;
1616 /* TODO: add checks on what other slapd-ldap(5) args
1617 * should be put in the template; this is not quite
1618 * harmful, because attributes that shouldn't don't
1619 * get actually used, but the user should at least
1623 be->bd_info = lback;
1624 be->be_private = (void *)lc->lc_cfg_li;
1625 be->be_cf_ocs = lback->bi_cf_ocs;
1627 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1629 argv[ 0 ] = save_argv0;
1630 be->be_cf_ocs = be_cf_ocs;
1631 be->be_private = be_private;
1632 be->bd_info = bd_info;
1634 if ( which_argv == 0 ) {
1640 db.be_private = (void *)lc->lc_cfg_li;
1641 ldap_chain_db_destroy_one( &db, NULL );
1642 lc->lc_cfg_li = NULL;
1645 if ( lc->lc_cfg_li->li_bvuri == NULL
1646 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1647 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1649 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1650 "no URI list allowed in slapo-chain.\n",
1653 goto private_destroy;
1656 if ( avl_insert( &lc->lc_lai.lai_tree,
1657 (caddr_t)lc->lc_cfg_li,
1658 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1660 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1661 "duplicate URI in slapo-chain.\n",
1664 goto private_destroy;
1681 typedef struct ldap_chain_db_apply_t {
1684 } ldap_chain_db_apply_t;
1687 ldap_chain_db_apply( void *datum, void *arg )
1689 ldapinfo_t *li = (ldapinfo_t *)datum;
1690 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1692 lca->be->be_private = (void *)li;
1694 return lca->func( lca->be, NULL );
1703 slap_overinst *on = (slap_overinst *)be->bd_info;
1704 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1709 BI_db_func *func = (&lback->bi_db_open)[ which ];
1711 if ( func != NULL && lc->lc_common_li != NULL ) {
1715 db.be_private = lc->lc_common_li;
1717 rc = func( &db, NULL );
1723 if ( lc->lc_lai.lai_tree != NULL ) {
1724 ldap_chain_db_apply_t lca;
1729 rc = avl_apply( lc->lc_lai.lai_tree,
1730 ldap_chain_db_apply, (void *)&lca,
1731 1, AVL_INORDER ) != AVL_NOMORE;
1744 slap_overinst *on = (slap_overinst *) be->bd_info;
1745 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1746 slap_mask_t monitoring;
1749 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1750 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1754 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1756 if ( lc->lc_common_li == NULL ) {
1757 void *be_private = be->be_private;
1758 ldap_chain_db_init_common( be );
1759 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1760 be->be_private = be_private;
1763 /* filter out and restore monitoring */
1764 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1765 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1766 rc = ldap_chain_db_func( be, db_open );
1767 SLAP_DBFLAGS( be ) |= monitoring;
1773 ldap_chain_db_close(
1777 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1778 #ifdef SLAP_CONFIG_DELETE
1779 overlay_unregister_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1780 #endif /* SLAP_CONFIG_DELETE */
1781 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1782 return ldap_chain_db_func( be, db_close );
1786 ldap_chain_db_destroy(
1790 slap_overinst *on = (slap_overinst *) be->bd_info;
1791 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1795 rc = ldap_chain_db_func( be, db_destroy );
1798 avl_free( lc->lc_lai.lai_tree, NULL );
1799 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1807 * inits one instance of the slapd-ldap backend, and stores
1808 * the private info in be_private of the arg
1811 ldap_chain_db_init_common(
1814 BackendInfo *bi = be->bd_info;
1818 be->bd_info = lback;
1819 be->be_private = NULL;
1820 rc = lback->bi_db_init( be, NULL );
1824 li = (ldapinfo_t *)be->be_private;
1825 li->li_urllist_f = NULL;
1826 li->li_urllist_p = NULL;
1834 * inits one instance of the slapd-ldap backend, stores
1835 * the private info in be_private of the arg and fills
1836 * selected fields with data from the template.
1838 * NOTE: add checks about the other fields of the template,
1839 * which are ignored and SHOULD NOT be configured by the user.
1842 ldap_chain_db_init_one(
1845 slap_overinst *on = (slap_overinst *)be->bd_info;
1846 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1848 BackendInfo *bi = be->bd_info;
1853 be->bd_info = lback;
1854 be->be_private = NULL;
1855 t = lback->bi_db_init( be, NULL );
1859 li = (ldapinfo_t *)be->be_private;
1860 li->li_urllist_f = NULL;
1861 li->li_urllist_p = NULL;
1863 /* copy common data */
1864 li->li_nretries = lc->lc_common_li->li_nretries;
1865 li->li_flags = lc->lc_common_li->li_flags;
1866 li->li_version = lc->lc_common_li->li_version;
1867 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
1868 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1876 ldap_chain_db_open_one(
1879 if ( SLAP_DBMONITORING( be ) ) {
1880 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
1882 if ( li->li_uri == NULL ) {
1883 ber_str2bv( "cn=Common Connections", 0, 1,
1884 &li->li_monitor_info.lmi_rdn );
1889 li->li_monitor_info.lmi_rdn.bv_len
1890 = STRLENOF( "cn=" ) + strlen( li->li_uri );
1891 ptr = li->li_monitor_info.lmi_rdn.bv_val
1892 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
1893 ptr = lutil_strcopy( ptr, "cn=" );
1894 ptr = lutil_strcopy( ptr, li->li_uri );
1899 return lback->bi_db_open( be, NULL );
1902 typedef struct ldap_chain_conn_apply_t {
1905 } ldap_chain_conn_apply_t;
1908 ldap_chain_conn_apply( void *datum, void *arg )
1910 ldapinfo_t *li = (ldapinfo_t *)datum;
1911 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1913 lca->be->be_private = (void *)li;
1915 return lback->bi_connection_destroy( lca->be, lca->conn );
1919 ldap_chain_connection_destroy(
1924 slap_overinst *on = (slap_overinst *) be->bd_info;
1925 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1926 void *private = be->be_private;
1927 ldap_chain_conn_apply_t lca;
1930 be->be_private = NULL;
1933 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1934 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1935 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1936 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1937 be->be_private = private;
1942 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1944 ldap_chain_parse_ctrl(
1954 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1955 rs->sr_text = "Chaining behavior control specified multiple times";
1956 return LDAP_PROTOCOL_ERROR;
1959 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1960 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1961 return LDAP_PROTOCOL_ERROR;
1964 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1965 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1970 /* Parse the control value
1971 * ChainingBehavior ::= SEQUENCE {
1972 * resolveBehavior Behavior OPTIONAL,
1973 * continuationBehavior Behavior OPTIONAL }
1975 * Behavior :: = ENUMERATED {
1976 * chainingPreferred (0),
1977 * chainingRequired (1),
1978 * referralsPreferred (2),
1979 * referralsRequired (3) }
1982 ber = ber_init( &ctrl->ldctl_value );
1984 rs->sr_text = "internal error";
1988 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1989 /* FIXME: since the whole SEQUENCE is optional,
1990 * should we accept no enumerations at all? */
1991 if ( tag != LBER_ENUMERATED ) {
1992 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1993 return LDAP_PROTOCOL_ERROR;
1996 switch ( behavior ) {
1997 case LDAP_CHAINING_PREFERRED:
1998 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
2001 case LDAP_CHAINING_REQUIRED:
2002 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
2005 case LDAP_REFERRALS_PREFERRED:
2006 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
2009 case LDAP_REFERRALS_REQUIRED:
2010 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2014 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2015 return LDAP_PROTOCOL_ERROR;
2018 tag = ber_peek_tag( ber, &len );
2019 if ( tag == LBER_ENUMERATED ) {
2020 tag = ber_scanf( ber, "e", &behavior );
2021 if ( tag == LBER_ERROR ) {
2022 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
2023 return LDAP_PROTOCOL_ERROR;
2027 if ( tag == LBER_DEFAULT ) {
2028 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2031 switch ( behavior ) {
2032 case LDAP_CHAINING_PREFERRED:
2033 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2036 case LDAP_CHAINING_REQUIRED:
2037 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2040 case LDAP_REFERRALS_PREFERRED:
2041 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2044 case LDAP_REFERRALS_REQUIRED:
2045 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2049 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2050 return LDAP_PROTOCOL_ERROR;
2054 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2055 rs->sr_text = "Chaining behavior control: decoding error";
2056 return LDAP_PROTOCOL_ERROR;
2059 (void) ber_free( ber, 1 );
2062 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2063 ? SLAP_CONTROL_CRITICAL
2064 : SLAP_CONTROL_NONCRITICAL );
2066 return LDAP_SUCCESS;
2068 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2071 chain_initialize( void )
2075 /* Make sure we don't exceed the bits reserved for userland */
2076 config_check_userland( CH_LAST );
2078 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2079 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2080 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2081 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2082 if ( rc != LDAP_SUCCESS ) {
2083 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2084 "unable to register chaining behavior control: %d.\n",
2088 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2090 ldapchain.on_bi.bi_type = "chain";
2091 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2092 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2093 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2094 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2095 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2097 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2099 ldapchain.on_response = ldap_chain_response;
2101 ldapchain.on_bi.bi_cf_ocs = chainocs;
2103 rc = config_register_schema( chaincfg, chainocs );
2108 return overlay_register( &ldapchain );