1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2009 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_private = &lb;
858 sc2.sc_response = ldap_chain_cb_response;
859 op->o_callback = &sc2;
861 /* Chaining can be performed by a privileged user on behalf
862 * of normal users, using the ProxyAuthz control, by exploiting
863 * the identity assertion feature of back-ldap; see idassert-*
864 * directives in slapd-ldap(5).
866 * FIXME: the idassert-authcDN is one, will it be fine regardless
867 * of the URI we obtain from the referral?
870 switch ( op->o_tag ) {
871 case LDAP_REQ_BIND: {
872 struct berval rndn = op->o_req_ndn;
873 Connection *conn = op->o_conn;
875 /* FIXME: can we really get a referral for binds? */
876 op->o_req_ndn = slap_empty_bv;
878 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
879 op->o_req_ndn = rndn;
885 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
888 case LDAP_REQ_DELETE:
889 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
892 case LDAP_REQ_MODRDN:
893 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
896 case LDAP_REQ_MODIFY:
897 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
900 case LDAP_REQ_COMPARE:
901 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
902 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
907 case LDAP_REQ_SEARCH:
908 if ( rs->sr_type == REP_SEARCHREF ) {
909 rc = ldap_chain_search( op, rs, ref, 0 );
912 /* we might get here before any database actually
913 * performed a search; in those cases, we need
914 * to check limits, to make sure safe defaults
916 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
917 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
920 rc = SLAP_CB_CONTINUE;
925 case LDAP_REQ_EXTENDED:
926 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
927 /* FIXME: ldap_back_extended() by design
928 * doesn't send result; frontend is expected
930 /* FIXME: what about chaining? */
931 if ( rc != SLAPD_ABANDON ) {
933 send_ldap_extended( op, rs );
936 lb.lb_status = LDAP_CH_RES;
940 rc = SLAP_CB_CONTINUE;
950 /* slapd-ldap sent response */
951 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
952 /* FIXME: should we send response? */
953 Debug( LDAP_DEBUG_ANY,
954 "%s: ldap_chain_response: "
955 "overlay should have sent result.\n",
956 op->o_log_prefix, 0, 0 );
961 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
962 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
966 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
967 case LDAP_CHAINING_REQUIRED:
969 op->o_callback = NULL;
970 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
971 "operation cannot be completed without chaining" );
975 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
976 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
978 rs->sr_type = sr_type;
981 rc = SLAP_CB_CONTINUE;
983 rs->sr_type = sr_type;
985 rs->sr_matched = matched;
988 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
991 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
994 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
995 op->o_callback = NULL;
996 rc = rs->sr_err = slap_map_api2result( rs );
997 send_ldap_result( op, rs );
1001 rs->sr_err = sr_err;
1002 rs->sr_type = sr_type;
1004 rs->sr_matched = matched;
1007 op->o_callback = sc;
1013 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1015 ldap_chain_parse_ctrl(
1018 LDAPControl *ctrl );
1021 str2chain( const char *s )
1023 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1024 return LDAP_CHAINING_PREFERRED;
1026 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1027 return LDAP_CHAINING_REQUIRED;
1029 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1030 return LDAP_REFERRALS_PREFERRED;
1032 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1033 return LDAP_REFERRALS_REQUIRED;
1038 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1053 static ConfigDriver chain_cf_gen;
1054 static ConfigCfAdd chain_cfadd;
1055 static ConfigLDAPadd chain_ldadd;
1057 static ConfigTable chaincfg[] = {
1058 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1059 { "chain-chaining", "args",
1060 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1061 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1062 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1063 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1064 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1065 { "chain-cache-uri", "TRUE/FALSE",
1066 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1067 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1068 "DESC 'Enables caching of URIs not present in configuration' "
1069 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1070 { "chain-max-depth", "args",
1071 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1072 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1073 "DESC 'max referral depth' "
1074 "SYNTAX OMsInteger "
1075 "EQUALITY integerMatch "
1076 "SINGLE-VALUE )", NULL, NULL },
1077 { "chain-return-error", "TRUE/FALSE",
1078 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1079 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1080 "DESC 'Errors are returned instead of the original referral' "
1081 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1082 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1085 static ConfigOCs chainocs[] = {
1086 { "( OLcfgOvOc:3.1 "
1087 "NAME 'olcChainConfig' "
1088 "DESC 'Chain configuration' "
1089 "SUP olcOverlayConfig "
1091 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1092 "olcChainingBehavior $ "
1093 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1094 "olcChainCacheURI $ "
1095 "olcChainMaxReferralDepth $ "
1096 "olcChainReturnError "
1098 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1099 { "( OLcfgOvOc:3.2 "
1100 "NAME 'olcChainDatabase' "
1101 "DESC 'Chain remote server configuration' "
1103 Cft_Misc, olcDatabaseDummy, chain_ldadd },
1108 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1115 AttributeDescription *ad = NULL;
1121 if ( p->ce_type != Cft_Overlay
1123 || p->ce_bi->bi_cf_ocs != chainocs )
1125 return LDAP_CONSTRAINT_VIOLATION;
1128 on = (slap_overinst *)p->ce_bi;
1129 lc = (ldap_chain_t *)on->on_bi.bi_private;
1131 assert( ca->be == NULL );
1132 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1134 ca->be->bd_info = (BackendInfo *)on;
1136 rc = slap_str2ad( "olcDbURI", &ad, &text );
1137 assert( rc == LDAP_SUCCESS );
1139 at = attr_find( e->e_attrs, ad );
1140 if ( lc->lc_common_li == NULL && at != NULL ) {
1141 /* FIXME: we should generate an empty default entry
1142 * if none is supplied */
1143 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1144 "first underlying database \"%s\" "
1145 "cannot contain attribute \"%s\".\n",
1146 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1147 rc = LDAP_CONSTRAINT_VIOLATION;
1150 } else if ( lc->lc_common_li != NULL && at == NULL ) {
1151 /* FIXME: we should generate an empty default entry
1152 * if none is supplied */
1153 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1154 "subsequent underlying database \"%s\" "
1155 "must contain attribute \"%s\".\n",
1156 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1157 rc = LDAP_CONSTRAINT_VIOLATION;
1161 if ( lc->lc_common_li == NULL ) {
1162 rc = ldap_chain_db_init_common( ca->be );
1165 rc = ldap_chain_db_init_one( ca->be );
1169 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1170 "unable to init %sunderlying database \"%s\".\n",
1171 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1172 return LDAP_CONSTRAINT_VIOLATION;
1175 li = ca->be->be_private;
1177 if ( lc->lc_common_li == NULL ) {
1178 lc->lc_common_li = li;
1181 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1182 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1183 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1184 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1186 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1187 "database \"%s\" insert failed.\n",
1188 e->e_name.bv_val, 0, 0 );
1189 rc = LDAP_CONSTRAINT_VIOLATION;
1194 ca->ca_private = on;
1197 if ( rc != LDAP_SUCCESS ) {
1198 (void)ldap_chain_db_destroy_one( ca->be, NULL );
1206 typedef struct ldap_chain_cfadd_apply_t {
1212 } ldap_chain_cfadd_apply_t;
1215 ldap_chain_cfadd_apply( void *datum, void *arg )
1217 ldapinfo_t *li = (ldapinfo_t *)datum;
1218 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1222 /* FIXME: should not hardcode "olcDatabase" here */
1223 bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
1224 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1225 bv.bv_val = lca->ca->cr_msg;
1227 lca->ca->be->be_private = (void *)li;
1228 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1229 &bv, lback->bi_cf_ocs, &chainocs[1] );
1237 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1239 CfEntryInfo *pe = p->e_private;
1240 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1241 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1242 void *priv = (void *)ca->be->be_private;
1244 if ( lback->bi_cf_ocs ) {
1245 ldap_chain_cfadd_apply_t lca = { 0 };
1253 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1255 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1256 &lca, 1, AVL_INORDER );
1258 ca->be->be_private = priv;
1264 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1265 static slap_verbmasks chaining_mode[] = {
1266 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1267 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1268 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1269 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1272 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1275 chain_cf_gen( ConfigArgs *c )
1277 slap_overinst *on = (slap_overinst *)c->bi;
1278 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1282 if ( c->op == SLAP_CONFIG_EMIT ) {
1284 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1286 struct berval resolve = BER_BVNULL,
1287 continuation = BER_BVNULL;
1289 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1293 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1294 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1296 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1298 + STRLENOF( "continuation=" ) + continuation.bv_len;
1299 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1300 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1301 "resolve=%s continuation=%s",
1302 resolve.bv_val, continuation.bv_val );
1304 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1305 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1306 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1307 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1308 " critical", STRLENOF( " critical" ) + 1 );
1309 c->value_bv.bv_len += STRLENOF( " critical" );
1314 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1317 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1321 c->value_int = lc->lc_max_depth;
1325 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1334 } else if ( c->op == LDAP_MOD_DELETE ) {
1340 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1348 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1359 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1360 char **argv = c->argv;
1362 BerElementBuffer berbuf;
1363 BerElement *ber = (BerElement *)&berbuf;
1367 Operation op = { 0 };
1368 SlapReply rs = { 0 };
1370 lc->lc_chaining_ctrlflag = 0;
1372 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1373 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1374 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1375 if ( resolve == -1 ) {
1376 Debug( LDAP_DEBUG_ANY, "%s: "
1377 "illegal <resolve> value %s "
1378 "in \"chain-chaining>\".\n",
1379 c->log, argv[ 0 ], 0 );
1383 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1384 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1385 if ( continuation == -1 ) {
1386 Debug( LDAP_DEBUG_ANY, "%s: "
1387 "illegal <continuation> value %s "
1388 "in \"chain-chaining\".\n",
1389 c->log, argv[ 0 ], 0 );
1393 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1397 Debug( LDAP_DEBUG_ANY, "%s: "
1398 "unknown option in \"chain-chaining\".\n",
1404 if ( resolve != -1 || continuation != -1 ) {
1407 if ( resolve == -1 ) {
1409 resolve = SLAP_CHAINING_DEFAULT;
1412 ber_init2( ber, NULL, LBER_USE_DER );
1414 err = ber_printf( ber, "{e" /* } */, resolve );
1417 Debug( LDAP_DEBUG_ANY, "%s: "
1418 "chaining behavior control encoding error!\n",
1423 if ( continuation > -1 ) {
1424 err = ber_printf( ber, "e", continuation );
1427 Debug( LDAP_DEBUG_ANY, "%s: "
1428 "chaining behavior control encoding error!\n",
1434 err = ber_printf( ber, /* { */ "N}" );
1437 Debug( LDAP_DEBUG_ANY, "%s: "
1438 "chaining behavior control encoding error!\n",
1443 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1444 exit( EXIT_FAILURE );
1448 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1451 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1452 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1454 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1456 Debug( LDAP_DEBUG_ANY, "%s: "
1457 "unable to parse chaining control%s%s.\n",
1458 c->log, rs.sr_text ? ": " : "",
1459 rs.sr_text ? rs.sr_text : "" );
1463 lc->lc_chaining_ctrlflag = op.o_chaining;
1465 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1468 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1469 Debug( LDAP_DEBUG_ANY, "%s: "
1470 "\"chaining\" control unsupported (ignored).\n",
1472 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1476 if ( c->value_int ) {
1477 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1479 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1484 if ( c->value_int < 0 ) {
1485 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1486 "<%s> invalid max referral depth %d",
1487 c->argv[0], c->value_int );
1488 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1489 c->log, c->cr_msg, 0 );
1493 lc->lc_max_depth = c->value_int;
1496 if ( c->value_int ) {
1497 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1499 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1515 slap_overinst *on = (slap_overinst *)be->bd_info;
1516 ldap_chain_t *lc = NULL;
1518 if ( lback == NULL ) {
1519 lback = backend_info( "ldap" );
1521 if ( lback == NULL ) {
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 )
2068 /* Make sure we don't exceed the bits reserved for userland */
2069 config_check_userland( CH_LAST );
2071 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2072 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2073 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2074 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2075 if ( rc != LDAP_SUCCESS ) {
2076 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2077 "unable to register chaining behavior control: %d.\n",
2081 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2083 ldapchain.on_bi.bi_type = "chain";
2084 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2085 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2086 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2087 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2088 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2090 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2092 ldapchain.on_response = ldap_chain_response;
2094 ldapchain.on_bi.bi_cf_ocs = chainocs;
2096 rc = config_register_schema( chaincfg, chainocs );
2101 return overlay_register( &ldapchain );