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 );
1411 avl_free( lc->lc_lai.lai_tree, NULL );
1419 ldap_chain_db_init_one(
1422 slap_overinst *on = (slap_overinst *)be->bd_info;
1423 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1430 db.be_private = NULL;
1431 t = lback->bi_db_init( &db );
1435 li = (ldapinfo_t *)db.be_private;
1437 /* copy common data */
1438 li->li_nretries = lc->lc_common_li->li_nretries;
1439 li->li_flags = lc->lc_common_li->li_flags;
1440 li->li_version = lc->lc_common_li->li_version;
1441 for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
1442 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1445 be->be_private = li;
1450 typedef struct ldap_chain_conn_apply_t {
1453 } ldap_chain_conn_apply_t;
1456 ldap_chain_conn_apply( void *datum, void *arg )
1458 ldapinfo_t *li = (ldapinfo_t *)datum;
1459 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1461 lca->be->be_private = (void *)li;
1463 return lback->bi_connection_destroy( lca->be, lca->conn );
1467 ldap_chain_connection_destroy(
1472 slap_overinst *on = (slap_overinst *) be->bd_info;
1473 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1474 void *private = be->be_private;
1475 ldap_chain_conn_apply_t lca;
1478 be->be_private = NULL;
1481 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1482 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1483 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1484 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1485 be->be_private = private;
1490 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1492 ldap_chain_parse_ctrl(
1502 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1503 rs->sr_text = "Chaining behavior control specified multiple times";
1504 return LDAP_PROTOCOL_ERROR;
1507 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1508 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1509 return LDAP_PROTOCOL_ERROR;
1512 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1513 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1518 /* Parse the control value
1519 * ChainingBehavior ::= SEQUENCE {
1520 * resolveBehavior Behavior OPTIONAL,
1521 * continuationBehavior Behavior OPTIONAL }
1523 * Behavior :: = ENUMERATED {
1524 * chainingPreferred (0),
1525 * chainingRequired (1),
1526 * referralsPreferred (2),
1527 * referralsRequired (3) }
1530 ber = ber_init( &ctrl->ldctl_value );
1532 rs->sr_text = "internal error";
1536 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1537 /* FIXME: since the whole SEQUENCE is optional,
1538 * should we accept no enumerations at all? */
1539 if ( tag != LBER_ENUMERATED ) {
1540 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1541 return LDAP_PROTOCOL_ERROR;
1544 switch ( behavior ) {
1545 case LDAP_CHAINING_PREFERRED:
1546 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1549 case LDAP_CHAINING_REQUIRED:
1550 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1553 case LDAP_REFERRALS_PREFERRED:
1554 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1557 case LDAP_REFERRALS_REQUIRED:
1558 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1562 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1563 return LDAP_PROTOCOL_ERROR;
1566 tag = ber_peek_tag( ber, &len );
1567 if ( tag == LBER_ENUMERATED ) {
1568 tag = ber_scanf( ber, "e", &behavior );
1569 if ( tag == LBER_ERROR ) {
1570 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1571 return LDAP_PROTOCOL_ERROR;
1575 if ( tag == LBER_DEFAULT ) {
1576 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1579 switch ( behavior ) {
1580 case LDAP_CHAINING_PREFERRED:
1581 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1584 case LDAP_CHAINING_REQUIRED:
1585 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1588 case LDAP_REFERRALS_PREFERRED:
1589 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1592 case LDAP_REFERRALS_REQUIRED:
1593 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1597 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1598 return LDAP_PROTOCOL_ERROR;
1602 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1603 rs->sr_text = "Chaining behavior control: decoding error";
1604 return LDAP_PROTOCOL_ERROR;
1607 (void) ber_free( ber, 1 );
1610 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1611 ? SLAP_CONTROL_CRITICAL
1612 : SLAP_CONTROL_NONCRITICAL );
1614 return LDAP_SUCCESS;
1616 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1618 static slap_overinst ldapchain;
1625 /* Make sure we don't exceed the bits reserved for userland */
1626 config_check_userland( CH_LAST );
1628 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1629 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1630 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1631 ldap_chain_parse_ctrl, &sc_chainingBehavior );
1632 if ( rc != LDAP_SUCCESS ) {
1633 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1634 "unable to register chaining behavior control: %d\n",
1638 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1640 ldapchain.on_bi.bi_type = "chain";
1641 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1642 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1643 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1644 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
1645 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1647 /* ... otherwise the underlying backend's function would be called,
1648 * likely passing an invalid entry; on the contrary, the requested
1649 * operational attributes should have been returned while chasing
1650 * the referrals. This all in all is a bit messy, because part
1651 * of the operational attributes are generated by the backend;
1652 * part by the frontend; back-ldap should receive all the available
1653 * ones from the remote server, but then, on its own, it strips those
1654 * it assumes will be (re)generated by the frontend (e.g.
1655 * subschemaSubentry.) */
1656 ldapchain.on_bi.bi_operational = ldap_chain_operational;
1658 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1660 ldapchain.on_response = ldap_chain_response;
1662 ldapchain.on_bi.bi_cf_ocs = chainocs;
1664 rc = config_register_schema( chaincfg, chainocs );
1669 return overlay_register( &ldapchain );