1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2005 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>
31 #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 */
61 #define LDAP_CH_NONE ((void *)(0))
62 #define LDAP_CH_RES ((void *)(1))
63 #define LDAP_CH_ERR ((void *)(2))
65 static BackendInfo *lback;
67 typedef struct ldap_chain_t {
69 * A "template" ldapinfo_t gets all common configuration items;
70 * then, for each configured URI, an entry is created in the tree;
71 * all the specific configuration items get in the current URI
74 * Then, for each referral, extract the URI and lookup the
75 * related structure. If configured to do so, allow URIs
76 * not found in the structure to create a temporary one
77 * that chains anonymously; maybe it can also be added to
78 * the tree? Should be all configurable.
81 /* "common" configuration info (all occurring before an "uri") */
82 ldapinfo_t *lc_common_li;
84 /* current configuration info */
85 ldapinfo_t *lc_cfg_li;
87 /* tree of configured[/generated?] "uri" info */
88 ldap_avl_info_t lc_lai;
91 #define LDAP_CHAIN_F_NONE (0x00U)
92 #define LDAP_CHAIN_F_CHAINING (0x01U)
93 #define LDAP_CHAIN_F_CACHE_URI (0x10U)
95 #define LDAP_CHAIN_CHAINING( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CHAINING ) == LDAP_CHAIN_F_CHAINING )
96 #define LDAP_CHAIN_CACHE_URI( lc ) ( ( (lc)->lc_flags & LDAP_CHAIN_F_CACHE_URI ) == LDAP_CHAIN_F_CACHE_URI )
98 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
99 LDAPControl lc_chaining_ctrl;
100 char lc_chaining_ctrlflag;
101 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
104 static int ldap_chain_db_init_one( BackendDB *be );
105 #define ldap_chain_db_open_one(be) (lback)->bi_db_open( (be) )
106 #define ldap_chain_db_close_one(be) (0)
107 #define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
109 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
111 chaining_control_add(
114 LDAPControl ***oldctrlsp )
116 LDAPControl **ctrls = NULL;
119 *oldctrlsp = op->o_ctrls;
121 /* default chaining control not defined */
122 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
126 /* already present */
127 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
131 /* FIXME: check other incompatibilities */
133 /* add to other controls */
135 for ( c = 0; op->o_ctrls[ c ]; c++ )
139 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
140 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
142 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
143 ctrls[ c + 1 ] = op->o_ctrls[ c ];
146 ctrls[ c + 1 ] = NULL;
150 op->o_chaining = lc->lc_chaining_ctrlflag;
156 chaining_control_remove(
158 LDAPControl ***oldctrlsp )
160 LDAPControl **oldctrls = *oldctrlsp;
162 /* we assume that the first control is the chaining control
163 * added by the chain overlay, so it's the only one we explicitly
165 if ( op->o_ctrls != oldctrls ) {
166 assert( op->o_ctrls != NULL );
167 assert( op->o_ctrls[ 0 ] != NULL );
172 op->o_ctrls = oldctrls;
179 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
182 ldap_chain_uri_cmp( const void *c1, const void *c2 )
184 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
185 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
187 assert( li1->li_bvuri != NULL );
188 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
189 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
191 assert( li2->li_bvuri != NULL );
192 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
193 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
195 /* If local DNs don't match, it is definitely not a match */
196 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
200 ldap_chain_uri_dup( void *c1, void *c2 )
202 ldapinfo_t *li1 = (ldapinfo_t *)c1;
203 ldapinfo_t *li2 = (ldapinfo_t *)c2;
205 assert( li1->li_bvuri != NULL );
206 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
207 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
209 assert( li2->li_bvuri != NULL );
210 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
211 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
213 /* Cannot have more than one shared session with same DN */
214 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
222 ldap_chain_operational( Operation *op, SlapReply *rs )
224 /* Trap entries generated by back-ldap.
226 * FIXME: we need a better way to recognize them; a cleaner
227 * solution would be to be able to intercept the response
228 * of be_operational(), so that we can divert only those
229 * calls that fail because operational attributes were
230 * requested for entries that do not belong to the underlying
231 * database. This fix is likely to intercept also entries
232 * generated by back-perl and so. */
233 if ( rs->sr_entry->e_private == NULL ) {
237 return SLAP_CB_CONTINUE;
241 * Search specific response that strips entryDN from entries
244 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
246 assert( op->o_tag == LDAP_REQ_SEARCH );
248 /* if in error, don't proceed any further */
249 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
253 if ( rs->sr_type == REP_SEARCH ) {
254 Attribute **ap = &rs->sr_entry->e_attrs;
256 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
257 /* will be generated later by frontend
258 * (a cleaner solution would be that
259 * the frontend checks if it already exists */
260 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
267 /* there SHOULD be one only! */
272 return SLAP_CB_CONTINUE;
274 } else if ( rs->sr_type == REP_SEARCHREF ) {
275 /* if we get it here, it means the library was unable
276 * to chase the referral... */
278 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
279 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
280 switch ( get_continuationBehavior( op ) ) {
281 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
282 op->o_callback->sc_private = LDAP_CH_ERR;
283 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
289 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
290 return SLAP_CB_CONTINUE;
292 } else if ( rs->sr_type == REP_RESULT ) {
293 /* back-ldap tried to send result */
294 op->o_callback->sc_private = LDAP_CH_RES;
301 * Dummy response that simply traces if back-ldap tried to send
302 * anything to the client
305 ldap_chain_cb_response( Operation *op, SlapReply *rs )
307 /* if in error, don't proceed any further */
308 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
312 if ( rs->sr_type == REP_RESULT ) {
313 switch ( rs->sr_err ) {
314 case LDAP_COMPARE_TRUE:
315 case LDAP_COMPARE_FALSE:
316 if ( op->o_tag != LDAP_REQ_COMPARE ) {
322 op->o_callback->sc_private = LDAP_CH_RES;
326 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
327 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
328 switch ( get_continuationBehavior( op ) ) {
329 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
330 op->o_callback->sc_private = LDAP_CH_ERR;
331 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
337 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
344 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
346 /* strip the entryDN attribute, but keep returning results */
347 (void)ldap_chain_cb_search_response( op, rs );
350 return SLAP_CB_CONTINUE;
357 int ( *op_f )( Operation *op, SlapReply *rs ),
360 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
361 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
362 ldapinfo_t li = *lc->lc_common_li, *lip = NULL;
363 struct berval bvuri[ 2 ] = { { 0 } };
365 /* NOTE: returned if ref is empty... */
368 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
369 LDAPControl **ctrls = NULL;
371 (void)chaining_control_add( lc, op, &ctrls );
372 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
375 for ( ; !BER_BVISNULL( ref ); ref++ ) {
380 /* We're setting the URI of the first referral;
381 * what if there are more?
383 Document: draft-ietf-ldapbis-protocol-27.txt
387 If the client wishes to progress the operation, it MUST follow the
388 referral by contacting one of the supported services. If multiple
389 URIs are present, the client assumes that any supported URI may be
390 used to progress the operation.
392 * so we actually need to follow exactly one,
393 * and we can assume any is fine.
396 /* parse reference and use
397 * proto://[host][:port]/ only */
398 rc = ldap_url_parse_ext( ref->bv_val, &srv );
399 if ( rc != LDAP_URL_SUCCESS ) {
405 /* remove DN essentially because later on
406 * ldap_initialize() will parse the URL
407 * as a comma-separated URL list */
408 save_dn = srv->lud_dn;
410 srv->lud_scope = LDAP_SCOPE_DEFAULT;
411 li.li_uri = ldap_url_desc2str( srv );
412 srv->lud_dn = save_dn;
413 ldap_free_urldesc( srv );
415 if ( li.li_uri == NULL ) {
421 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
423 /* Searches for a ldapinfo in the avl tree */
424 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
425 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
426 (caddr_t)&li, ldap_chain_uri_cmp );
427 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
430 op->o_bd->be_private = (void *)lip;
433 rc = ldap_chain_db_init_one( op->o_bd );
437 lip = (ldapinfo_t *)op->o_bd->be_private;
438 lip->li_uri = li.li_uri;
439 lip->li_bvuri = bvuri;
440 rc = ldap_chain_db_open_one( op->o_bd );
442 (void)ldap_chain_db_destroy_one( op->o_bd );
446 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
447 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
448 if ( avl_insert( &lc->lc_lai.lai_tree,
449 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
451 /* someone just inserted another;
452 * don't bother, use this and then
456 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
463 rc = ( *op_f )( op, rs );
466 ldap_memfree( li.li_uri );
471 lip->li_bvuri = NULL;
472 (void)ldap_chain_db_close_one( op->o_bd );
473 (void)ldap_chain_db_destroy_one( op->o_bd );
476 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
481 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
482 (void)chaining_control_remove( op, &ctrls );
483 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
489 ldap_chain_response( Operation *op, SlapReply *rs )
491 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
492 void *private = op->o_bd->be_private;
493 slap_callback *sc = op->o_callback,
498 struct berval ndn = op->o_ndn;
500 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
501 int sr_err = rs->sr_err;
502 slap_reply_t sr_type = rs->sr_type;
503 slap_mask_t chain_mask = 0;
504 ber_len_t chain_shift = 0;
505 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
507 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
508 return SLAP_CB_CONTINUE;
511 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
512 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
513 switch ( get_resolveBehavior( op ) ) {
514 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
515 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
516 return SLAP_CB_CONTINUE;
519 chain_mask = SLAP_CH_RESOLVE_MASK;
520 chain_shift = SLAP_CH_RESOLVE_SHIFT;
524 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
525 switch ( get_continuationBehavior( op ) ) {
526 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
527 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
528 return SLAP_CB_CONTINUE;
531 chain_mask = SLAP_CH_CONTINUATION_MASK;
532 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
536 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
539 * TODO: add checks on who/when chain operations; e.g.:
540 * a) what identities are authorized
541 * b) what request DN (e.g. only chain requests rooted at <DN>)
542 * c) what referral URIs
543 * d) what protocol scheme (e.g. only ldaps://)
547 matched = rs->sr_matched;
548 rs->sr_matched = NULL;
552 /* we need this to know if back-ldap returned any result */
553 sc2.sc_response = ldap_chain_cb_response;
554 op->o_callback = &sc2;
556 /* Chaining can be performed by a privileged user on behalf
557 * of normal users, using the ProxyAuthz control, by exploiting
558 * the identity assertion feature of back-ldap; see idassert-*
559 * directives in slapd-ldap(5).
561 * FIXME: the idassert-authcDN is one, will it be fine regardless
562 * of the URI we obtain from the referral?
565 switch ( op->o_tag ) {
566 case LDAP_REQ_BIND: {
567 struct berval rndn = op->o_req_ndn;
568 Connection *conn = op->o_conn;
570 /* FIXME: can we really get a referral for binds? */
571 op->o_req_ndn = slap_empty_bv;
573 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
574 op->o_req_ndn = rndn;
580 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
583 case LDAP_REQ_DELETE:
584 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
587 case LDAP_REQ_MODRDN:
588 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
591 case LDAP_REQ_MODIFY:
592 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
595 case LDAP_REQ_COMPARE:
596 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
597 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
602 case LDAP_REQ_SEARCH:
603 if ( rs->sr_type == REP_SEARCHREF ) {
604 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
605 ldapinfo_t li = *lc->lc_common_li, *lip = NULL;
606 struct berval bvuri[ 2 ] = { { 0 } };
608 struct berval *curr = ref,
610 ondn = op->o_req_ndn;
612 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
613 LDAPControl **ctrls = NULL;
615 (void)chaining_control_add( lc, op, &ctrls );
616 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
618 rs->sr_type = REP_SEARCH;
620 sc2.sc_response = ldap_chain_cb_search_response;
622 /* if we parse the URI then by no means
623 * we can cache stuff or reuse connections,
624 * because in back-ldap there's no caching
625 * based on the URI value, which is supposed
626 * to be set once for all (correct?) */
628 for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
633 /* parse reference and use
634 * proto://[host][:port]/ only */
635 rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
636 if ( rc != LDAP_URL_SUCCESS ) {
638 rs->sr_err = LDAP_OTHER;
642 /* remove DN essentially because later on
643 * ldap_initialize() will parse the URL
644 * as a comma-separated URL list */
645 save_dn = srv->lud_dn;
647 srv->lud_scope = LDAP_SCOPE_DEFAULT;
648 li.li_uri = ldap_url_desc2str( srv );
649 if ( li.li_uri != NULL ) {
650 ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
652 ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
656 srv->lud_dn = save_dn;
657 ldap_free_urldesc( srv );
659 if ( li.li_uri == NULL ) {
661 rs->sr_err = LDAP_OTHER;
665 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
667 /* Searches for a ldapinfo in the avl tree */
668 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
669 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
670 (caddr_t)&li, ldap_chain_uri_cmp );
671 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
674 op->o_bd->be_private = (void *)lip;
677 /* if none is found, create a temporary... */
678 rc = ldap_chain_db_init_one( op->o_bd );
682 lip = (ldapinfo_t *)op->o_bd->be_private;
683 lip->li_uri = li.li_uri;
684 lip->li_bvuri = bvuri;
685 rc = ldap_chain_db_open_one( op->o_bd );
687 (void)ldap_chain_db_destroy_one( op->o_bd );
691 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
692 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
693 if ( avl_insert( &lc->lc_lai.lai_tree,
694 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
696 /* someone just inserted another;
697 * don't bother, use this and then
701 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
708 /* FIXME: should we also copy filter and scope?
709 * according to RFC3296, no */
710 rc = lback->bi_op_search( op, rs );
713 ldap_memfree( li.li_uri );
716 op->o_tmpfree( op->o_req_dn.bv_val,
718 op->o_tmpfree( op->o_req_ndn.bv_val,
723 lip->li_bvuri = NULL;
724 (void)ldap_chain_db_close_one( op->o_bd );
725 (void)ldap_chain_db_destroy_one( op->o_bd );
728 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
735 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
736 (void)chaining_control_remove( op, &ctrls );
737 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
740 op->o_req_ndn = ondn;
741 rs->sr_type = REP_SEARCHREF;
744 if ( rc != LDAP_SUCCESS ) {
745 /* couldn't chase any of the referrals */
746 rc = SLAP_CB_CONTINUE;
750 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
754 case LDAP_REQ_EXTENDED:
755 rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
756 /* FIXME: ldap_back_extended() by design
757 * doesn't send result; frontend is expected
759 /* FIXME: what aboit chaining? */
760 if ( rc != SLAPD_ABANDON ) {
761 send_ldap_extended( op, rs );
764 sc2.sc_private = LDAP_CH_RES;
768 rc = SLAP_CB_CONTINUE;
778 /* slapd-ldap sent response */
779 assert( sc2.sc_private == LDAP_CH_RES );
783 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
784 if ( sc2.sc_private == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
788 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
789 case LDAP_CHAINING_REQUIRED:
791 op->o_callback = NULL;
792 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
793 "operation cannot be completed without chaining" );
797 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
798 rc = SLAP_CB_CONTINUE;
800 rs->sr_type = sr_type;
801 rs->sr_matched = matched;
803 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
806 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
809 if ( sc2.sc_private == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
810 op->o_callback = NULL;
811 rc = rs->sr_err = slap_map_api2result( rs );
812 send_ldap_result( op, rs );
815 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
817 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
819 rs->sr_type = sr_type;
820 rs->sr_matched = matched;
822 op->o_bd->be_private = private;
829 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
831 ldap_chain_parse_ctrl(
837 str2chain( const char *s )
839 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
840 return LDAP_CHAINING_PREFERRED;
842 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
843 return LDAP_CHAINING_REQUIRED;
845 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
846 return LDAP_REFERRALS_PREFERRED;
848 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
849 return LDAP_REFERRALS_REQUIRED;
854 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
867 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
868 static ConfigDriver chain_cf_gen;
870 static ConfigCfAdd chain_cfadd;
871 static ConfigLDAPadd chain_ldadd;
873 static ConfigTable chaincfg[] = {
874 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
875 { "chain-chaining", "args",
876 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
877 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
878 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
879 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
880 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
881 { "chain-cache-uris", "TRUE/FALSE",
882 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
883 "( OLcfgOvAt:3.2 NAME 'olcCacheURIs' "
884 "DESC 'Enables caching of URIs not present in configuration' "
885 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
886 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
889 static ConfigOCs chainocs[] = {
890 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
892 "NAME 'olcChainConfig' "
893 "DESC 'Chain configuration' "
894 "SUP olcOverlayConfig "
895 "MAY ( olcChainingBehavior "
898 Cft_Overlay, chaincfg, NULL, chain_cfadd },
901 "NAME 'olcChainDatabase' "
902 "DESC 'Chain remote server configuration' "
904 Cft_Misc, chaincfg, chain_ldadd },
909 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
911 if ( p->ce_type != Cft_Overlay
913 || p->ce_bi->bi_cf_ocs != chainocs )
915 return LDAP_CONSTRAINT_VIOLATION;
921 typedef struct ldap_chain_cfadd_apply_t {
927 } ldap_chain_cfadd_apply_t;
930 ldap_chain_cfadd_apply( void *datum, void *arg )
932 ldapinfo_t *li = (ldapinfo_t *)datum;
933 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
937 /* FIXME: should not hardcode "olcDatabase" here */
938 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
939 "olcDatabase={%d}%s", lca->count, lback->bi_type );
940 bv.bv_val = lca->ca->msg;
942 lca->ca->be->be_private = (void *)li;
943 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
944 &bv, lback->bi_cf_ocs, &chainocs[1] );
952 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
954 CfEntryInfo *pe = p->e_private;
955 slap_overinst *on = (slap_overinst *)pe->ce_bi;
956 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
957 void *priv = (void *)ca->be->be_private;
959 if ( lback->bi_cf_ocs ) {
960 ldap_chain_cfadd_apply_t lca = { 0 };
968 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
970 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
971 &lca, 1, AVL_INORDER );
973 ca->be->be_private = priv;
979 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
981 static slap_verbmasks chaining_mode[] = {
982 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
983 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
984 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
985 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
990 chain_cf_gen( ConfigArgs *c )
992 slap_overinst *on = (slap_overinst *)c->bi;
993 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
994 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
999 if ( c->op == SLAP_CONFIG_EMIT ) {
1001 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1003 struct berval resolve = BER_BVNULL,
1004 continuation = BER_BVNULL;
1006 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1010 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1011 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1013 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1015 + STRLENOF( "continuation=" ) + continuation.bv_len;
1016 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1017 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1018 "resolve=%s continuation=%s",
1019 resolve.bv_val, continuation.bv_val );
1021 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1022 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1023 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1024 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1025 " critical", STRLENOF( " critical" ) + 1 );
1026 c->value_bv.bv_len += STRLENOF( " critical" );
1031 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1034 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1043 } else if ( c->op == LDAP_MOD_DELETE ) {
1049 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1059 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1061 char **argv = c->argv;
1063 BerElementBuffer berbuf;
1064 BerElement *ber = (BerElement *)&berbuf;
1068 Operation op = { 0 };
1069 SlapReply rs = { 0 };
1071 lc->lc_chaining_ctrlflag = 0;
1073 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1074 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1075 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1076 if ( resolve == -1 ) {
1077 fprintf( stderr, "%s line %d: "
1078 "illegal <resolve> value %s "
1079 "in \"chain-chaining>\"\n",
1080 c->fname, c->lineno, argv[ 0 ] );
1084 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1085 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1086 if ( continuation == -1 ) {
1087 fprintf( stderr, "%s line %d: "
1088 "illegal <continuation> value %s "
1089 "in \"chain-chaining\"\n",
1090 c->fname, c->lineno, argv[ 0 ] );
1094 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1098 fprintf( stderr, "%s line %d: "
1099 "unknown option in \"chain-chaining\"\n",
1100 c->fname, c->lineno );
1105 if ( resolve != -1 || continuation != -1 ) {
1108 if ( resolve == -1 ) {
1110 resolve = SLAP_CHAINING_DEFAULT;
1113 ber_init2( ber, NULL, LBER_USE_DER );
1115 err = ber_printf( ber, "{e" /* } */, resolve );
1118 fprintf( stderr, "%s line %d: "
1119 "chaining behavior control encoding error!\n",
1120 c->fname, c->lineno );
1124 if ( continuation > -1 ) {
1125 err = ber_printf( ber, "e", continuation );
1128 fprintf( stderr, "%s line %d: "
1129 "chaining behavior control encoding error!\n",
1130 c->fname, c->lineno );
1135 err = ber_printf( ber, /* { */ "N}" );
1138 fprintf( stderr, "%s line %d: "
1139 "chaining behavior control encoding error!\n",
1140 c->fname, c->lineno );
1144 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1145 exit( EXIT_FAILURE );
1149 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1152 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1153 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1155 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1157 fprintf( stderr, "%s line %d: "
1158 "unable to parse chaining control%s%s\n",
1159 c->fname, c->lineno,
1160 rs.sr_text ? ": " : "",
1161 rs.sr_text ? rs.sr_text : "" );
1165 lc->lc_chaining_ctrlflag = op.o_chaining;
1167 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1173 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1176 if ( c->value_int ) {
1177 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1179 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1190 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1196 slap_overinst *on = (slap_overinst *)be->bd_info;
1197 ldap_chain_t *lc = NULL;
1201 if ( lback == NULL ) {
1202 lback = backend_info( "ldap" );
1204 if ( lback == NULL ) {
1209 lc = ch_malloc( sizeof( ldap_chain_t ) );
1210 memset( lc, 0, sizeof( ldap_chain_t ) );
1212 bd.be_private = NULL;
1213 rc = lback->bi_db_init( &bd );
1214 lc->lc_cfg_li = lc->lc_common_li = (ldapinfo_t *)bd.be_private;
1215 on->on_bi.bi_private = (void *)lc;
1221 ldap_chain_db_config(
1228 slap_overinst *on = (slap_overinst *)be->bd_info;
1229 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1231 int rc = SLAP_CONF_UNKNOWN;
1233 /* Something for the cache database? */
1234 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1235 char *save_argv0 = argv[ 0 ];
1236 BackendInfo *bd_info = bd_info;
1237 void *be_private = be->be_private;
1238 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1241 argv[ 0 ] += STRLENOF( "chain-" );
1243 /* TODO: create a new structure and, after parsing the URI,
1244 * put it in the lc->lc_lai tree */
1245 if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
1246 rc = ldap_chain_db_init_one( be );
1248 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1249 "underlying slapd-ldap initialization failed\n.",
1253 lc->lc_cfg_li = be->be_private;
1257 be->bd_info = lback;
1258 be->be_private = (void *)lc->lc_cfg_li;
1259 be->be_cf_ocs = lback->bi_cf_ocs;
1261 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1263 argv[ 0 ] = save_argv0;
1264 be->be_cf_ocs = be_cf_ocs;
1265 be->be_private = be_private;
1266 be->bd_info = bd_info;
1274 db.be_private = (void *)lc->lc_cfg_li;
1275 ldap_chain_db_destroy_one( &db );
1276 lc->lc_cfg_li = NULL;
1279 if ( lc->lc_cfg_li->li_bvuri == NULL
1280 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1281 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1283 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1284 "no URI list allowed in slapo-chain.\n",
1287 goto private_destroy;
1290 if ( avl_insert( &lc->lc_lai.lai_tree,
1291 (caddr_t)lc->lc_cfg_li,
1292 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1294 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1295 "duplicate URI in slapo-chain.\n",
1298 goto private_destroy;
1315 typedef struct ldap_chain_db_apply_t {
1318 } ldap_chain_db_apply_t;
1321 ldap_chain_db_apply( void *datum, void *arg )
1323 ldapinfo_t *li = (ldapinfo_t *)datum;
1324 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1326 lca->be->be_private = (void *)li;
1328 return lca->func( lca->be );
1337 slap_overinst *on = (slap_overinst *)be->bd_info;
1338 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1343 BI_db_func *func = (&lback->bi_db_open)[ which ];
1345 if ( func != NULL ) {
1349 db.be_private = lc->lc_common_li;
1357 if ( lc->lc_lai.lai_tree != NULL ) {
1358 ldap_chain_db_apply_t lca;
1363 rc = avl_apply( lc->lc_lai.lai_tree,
1364 ldap_chain_db_apply, (void *)&lca,
1365 1, AVL_INORDER ) != AVL_NOMORE;
1377 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1380 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1384 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1386 /* FIXME: right now slapd-ldap has no open function;
1387 * in case one is introduced, this needs be fixed */
1389 return ldap_chain_db_func( be, db_open );
1393 ldap_chain_db_close(
1396 return ldap_chain_db_func( be, db_close );
1400 ldap_chain_db_destroy(
1403 slap_overinst *on = (slap_overinst *) be->bd_info;
1404 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1408 rc = ldap_chain_db_func( be, db_destroy );
1418 ldap_chain_db_init_one(
1421 slap_overinst *on = (slap_overinst *)be->bd_info;
1422 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1429 db.be_private = NULL;
1430 t = lback->bi_db_init( &db );
1434 li = (ldapinfo_t *)db.be_private;
1436 /* copy common data */
1437 li->li_nretries = lc->lc_common_li->li_nretries;
1438 li->li_flags = lc->lc_common_li->li_flags;
1439 li->li_version = lc->lc_common_li->li_version;
1440 for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
1441 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1444 be->be_private = li;
1449 typedef struct ldap_chain_conn_apply_t {
1452 } ldap_chain_conn_apply_t;
1455 ldap_chain_conn_apply( void *datum, void *arg )
1457 ldapinfo_t *li = (ldapinfo_t *)datum;
1458 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1460 lca->be->be_private = (void *)li;
1462 return lback->bi_connection_destroy( lca->be, lca->conn );
1466 ldap_chain_connection_destroy(
1471 slap_overinst *on = (slap_overinst *) be->bd_info;
1472 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1473 void *private = be->be_private;
1474 ldap_chain_conn_apply_t lca;
1477 be->be_private = NULL;
1480 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1481 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1482 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1483 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1484 be->be_private = private;
1489 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1491 ldap_chain_parse_ctrl(
1501 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1502 rs->sr_text = "Chaining behavior control specified multiple times";
1503 return LDAP_PROTOCOL_ERROR;
1506 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1507 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1508 return LDAP_PROTOCOL_ERROR;
1511 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1512 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1517 /* Parse the control value
1518 * ChainingBehavior ::= SEQUENCE {
1519 * resolveBehavior Behavior OPTIONAL,
1520 * continuationBehavior Behavior OPTIONAL }
1522 * Behavior :: = ENUMERATED {
1523 * chainingPreferred (0),
1524 * chainingRequired (1),
1525 * referralsPreferred (2),
1526 * referralsRequired (3) }
1529 ber = ber_init( &ctrl->ldctl_value );
1531 rs->sr_text = "internal error";
1535 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1536 /* FIXME: since the whole SEQUENCE is optional,
1537 * should we accept no enumerations at all? */
1538 if ( tag != LBER_ENUMERATED ) {
1539 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1540 return LDAP_PROTOCOL_ERROR;
1543 switch ( behavior ) {
1544 case LDAP_CHAINING_PREFERRED:
1545 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1548 case LDAP_CHAINING_REQUIRED:
1549 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1552 case LDAP_REFERRALS_PREFERRED:
1553 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1556 case LDAP_REFERRALS_REQUIRED:
1557 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1561 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1562 return LDAP_PROTOCOL_ERROR;
1565 tag = ber_peek_tag( ber, &len );
1566 if ( tag == LBER_ENUMERATED ) {
1567 tag = ber_scanf( ber, "e", &behavior );
1568 if ( tag == LBER_ERROR ) {
1569 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1570 return LDAP_PROTOCOL_ERROR;
1574 if ( tag == LBER_DEFAULT ) {
1575 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1578 switch ( behavior ) {
1579 case LDAP_CHAINING_PREFERRED:
1580 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1583 case LDAP_CHAINING_REQUIRED:
1584 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1587 case LDAP_REFERRALS_PREFERRED:
1588 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1591 case LDAP_REFERRALS_REQUIRED:
1592 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1596 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1597 return LDAP_PROTOCOL_ERROR;
1601 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1602 rs->sr_text = "Chaining behavior control: decoding error";
1603 return LDAP_PROTOCOL_ERROR;
1606 (void) ber_free( ber, 1 );
1609 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1610 ? SLAP_CONTROL_CRITICAL
1611 : SLAP_CONTROL_NONCRITICAL );
1613 return LDAP_SUCCESS;
1615 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1617 static slap_overinst ldapchain;
1624 /* Make sure we don't exceed the bits reserved for userland */
1625 config_check_userland( CH_LAST );
1627 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1628 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1629 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1630 ldap_chain_parse_ctrl, &sc_chainingBehavior );
1631 if ( rc != LDAP_SUCCESS ) {
1632 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1633 "unable to register chaining behavior control: %d\n",
1637 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1639 ldapchain.on_bi.bi_type = "chain";
1640 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1641 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1642 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1643 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
1644 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1646 /* ... otherwise the underlying backend's function would be called,
1647 * likely passing an invalid entry; on the contrary, the requested
1648 * operational attributes should have been returned while chasing
1649 * the referrals. This all in all is a bit messy, because part
1650 * of the operational attributes are generated by the backend;
1651 * part by the frontend; back-ldap should receive all the available
1652 * ones from the remote server, but then, on its own, it strips those
1653 * it assumes will be (re)generated by the frontend (e.g.
1654 * subschemaSubentry.) */
1655 ldapchain.on_bi.bi_operational = ldap_chain_operational;
1657 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1659 ldapchain.on_response = ldap_chain_response;
1661 ldapchain.on_bi.bi_cf_ocs = chainocs;
1663 rc = config_register_schema( chaincfg, chainocs );
1668 return overlay_register( &ldapchain );