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_common( BackendDB *be );
105 static int ldap_chain_db_init_one( BackendDB *be );
106 #define ldap_chain_db_open_one(be) (lback)->bi_db_open( (be) )
107 #define ldap_chain_db_close_one(be) (0)
108 #define ldap_chain_db_destroy_one(be) (lback)->bi_db_destroy( (be) )
110 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
112 chaining_control_add(
115 LDAPControl ***oldctrlsp )
117 LDAPControl **ctrls = NULL;
120 *oldctrlsp = op->o_ctrls;
122 /* default chaining control not defined */
123 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
127 /* already present */
128 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
132 /* FIXME: check other incompatibilities */
134 /* add to other controls */
136 for ( c = 0; op->o_ctrls[ c ]; c++ )
140 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
141 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
143 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
144 ctrls[ c + 1 ] = op->o_ctrls[ c ];
147 ctrls[ c + 1 ] = NULL;
151 op->o_chaining = lc->lc_chaining_ctrlflag;
157 chaining_control_remove(
159 LDAPControl ***oldctrlsp )
161 LDAPControl **oldctrls = *oldctrlsp;
163 /* we assume that the first control is the chaining control
164 * added by the chain overlay, so it's the only one we explicitly
166 if ( op->o_ctrls != oldctrls ) {
167 assert( op->o_ctrls != NULL );
168 assert( op->o_ctrls[ 0 ] != NULL );
173 op->o_ctrls = oldctrls;
180 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
183 ldap_chain_uri_cmp( const void *c1, const void *c2 )
185 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
186 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
188 assert( li1->li_bvuri != NULL );
189 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
190 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
192 assert( li2->li_bvuri != NULL );
193 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
194 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
196 /* If local DNs don't match, it is definitely not a match */
197 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
201 ldap_chain_uri_dup( void *c1, void *c2 )
203 ldapinfo_t *li1 = (ldapinfo_t *)c1;
204 ldapinfo_t *li2 = (ldapinfo_t *)c2;
206 assert( li1->li_bvuri != NULL );
207 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
208 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
210 assert( li2->li_bvuri != NULL );
211 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
212 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
214 /* Cannot have more than one shared session with same DN */
215 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
223 ldap_chain_operational( Operation *op, SlapReply *rs )
225 /* Trap entries generated by back-ldap.
227 * FIXME: we need a better way to recognize them; a cleaner
228 * solution would be to be able to intercept the response
229 * of be_operational(), so that we can divert only those
230 * calls that fail because operational attributes were
231 * requested for entries that do not belong to the underlying
232 * database. This fix is likely to intercept also entries
233 * generated by back-perl and so. */
234 if ( rs->sr_entry->e_private == NULL ) {
238 return SLAP_CB_CONTINUE;
242 * Search specific response that strips entryDN from entries
245 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
247 assert( op->o_tag == LDAP_REQ_SEARCH );
249 /* if in error, don't proceed any further */
250 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
254 if ( rs->sr_type == REP_SEARCH ) {
255 Attribute **ap = &rs->sr_entry->e_attrs;
257 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
258 /* will be generated later by frontend
259 * (a cleaner solution would be that
260 * the frontend checks if it already exists */
261 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
268 /* there SHOULD be one only! */
273 return SLAP_CB_CONTINUE;
275 } else if ( rs->sr_type == REP_SEARCHREF ) {
276 /* if we get it here, it means the library was unable
277 * to chase the referral... */
279 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
280 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
281 switch ( get_continuationBehavior( op ) ) {
282 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
283 op->o_callback->sc_private = LDAP_CH_ERR;
284 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
290 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
291 return SLAP_CB_CONTINUE;
293 } else if ( rs->sr_type == REP_RESULT ) {
294 /* back-ldap tried to send result */
295 op->o_callback->sc_private = LDAP_CH_RES;
302 * Dummy response that simply traces if back-ldap tried to send
303 * anything to the client
306 ldap_chain_cb_response( Operation *op, SlapReply *rs )
308 /* if in error, don't proceed any further */
309 if ( op->o_callback->sc_private == LDAP_CH_ERR ) {
313 if ( rs->sr_type == REP_RESULT ) {
314 switch ( rs->sr_err ) {
315 case LDAP_COMPARE_TRUE:
316 case LDAP_COMPARE_FALSE:
317 if ( op->o_tag != LDAP_REQ_COMPARE ) {
323 op->o_callback->sc_private = LDAP_CH_RES;
327 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
328 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
329 switch ( get_continuationBehavior( op ) ) {
330 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
331 op->o_callback->sc_private = LDAP_CH_ERR;
332 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
338 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
345 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
347 /* strip the entryDN attribute, but keep returning results */
348 (void)ldap_chain_cb_search_response( op, rs );
351 return SLAP_CB_CONTINUE;
358 int ( *op_f )( Operation *op, SlapReply *rs ),
361 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
362 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
363 ldapinfo_t li = { 0 }, *lip = NULL;
364 struct berval bvuri[ 2 ] = { { 0 } };
366 /* NOTE: returned if ref is empty... */
369 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
370 LDAPControl **ctrls = NULL;
372 (void)chaining_control_add( lc, op, &ctrls );
373 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
376 for ( ; !BER_BVISNULL( ref ); ref++ ) {
381 /* We're setting the URI of the first referral;
382 * what if there are more?
384 Document: draft-ietf-ldapbis-protocol-27.txt
388 If the client wishes to progress the operation, it MUST follow the
389 referral by contacting one of the supported services. If multiple
390 URIs are present, the client assumes that any supported URI may be
391 used to progress the operation.
393 * so we actually need to follow exactly one,
394 * and we can assume any is fine.
397 /* parse reference and use
398 * proto://[host][:port]/ only */
399 rc = ldap_url_parse_ext( ref->bv_val, &srv );
400 if ( rc != LDAP_URL_SUCCESS ) {
406 /* remove DN essentially because later on
407 * ldap_initialize() will parse the URL
408 * as a comma-separated URL list */
409 save_dn = srv->lud_dn;
411 srv->lud_scope = LDAP_SCOPE_DEFAULT;
412 li.li_uri = ldap_url_desc2str( srv );
413 srv->lud_dn = save_dn;
414 ldap_free_urldesc( srv );
416 if ( li.li_uri == NULL ) {
422 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
424 /* Searches for a ldapinfo in the avl tree */
425 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
426 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
427 (caddr_t)&li, ldap_chain_uri_cmp );
428 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
431 op->o_bd->be_private = (void *)lip;
434 rc = ldap_chain_db_init_one( op->o_bd );
438 lip = (ldapinfo_t *)op->o_bd->be_private;
439 lip->li_uri = li.li_uri;
440 lip->li_bvuri = bvuri;
441 rc = ldap_chain_db_open_one( op->o_bd );
443 (void)ldap_chain_db_destroy_one( op->o_bd );
447 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
448 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
449 if ( avl_insert( &lc->lc_lai.lai_tree,
450 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
452 /* someone just inserted another;
453 * don't bother, use this and then
457 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
464 rc = ( *op_f )( op, rs );
467 ldap_memfree( li.li_uri );
472 lip->li_bvuri = NULL;
473 (void)ldap_chain_db_close_one( op->o_bd );
474 (void)ldap_chain_db_destroy_one( op->o_bd );
477 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
482 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
483 (void)chaining_control_remove( op, &ctrls );
484 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
490 ldap_chain_response( Operation *op, SlapReply *rs )
492 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
493 void *private = op->o_bd->be_private;
494 slap_callback *sc = op->o_callback,
499 struct berval ndn = op->o_ndn;
501 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
502 int sr_err = rs->sr_err;
503 slap_reply_t sr_type = rs->sr_type;
504 slap_mask_t chain_mask = 0;
505 ber_len_t chain_shift = 0;
506 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
508 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
509 return SLAP_CB_CONTINUE;
512 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
513 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
514 switch ( get_resolveBehavior( op ) ) {
515 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
516 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
517 return SLAP_CB_CONTINUE;
520 chain_mask = SLAP_CH_RESOLVE_MASK;
521 chain_shift = SLAP_CH_RESOLVE_SHIFT;
525 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
526 switch ( get_continuationBehavior( op ) ) {
527 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
528 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
529 return SLAP_CB_CONTINUE;
532 chain_mask = SLAP_CH_CONTINUATION_MASK;
533 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
537 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
540 * TODO: add checks on who/when chain operations; e.g.:
541 * a) what identities are authorized
542 * b) what request DN (e.g. only chain requests rooted at <DN>)
543 * c) what referral URIs
544 * d) what protocol scheme (e.g. only ldaps://)
548 matched = rs->sr_matched;
549 rs->sr_matched = NULL;
553 /* we need this to know if back-ldap returned any result */
554 sc2.sc_response = ldap_chain_cb_response;
555 op->o_callback = &sc2;
557 /* Chaining can be performed by a privileged user on behalf
558 * of normal users, using the ProxyAuthz control, by exploiting
559 * the identity assertion feature of back-ldap; see idassert-*
560 * directives in slapd-ldap(5).
562 * FIXME: the idassert-authcDN is one, will it be fine regardless
563 * of the URI we obtain from the referral?
566 switch ( op->o_tag ) {
567 case LDAP_REQ_BIND: {
568 struct berval rndn = op->o_req_ndn;
569 Connection *conn = op->o_conn;
571 /* FIXME: can we really get a referral for binds? */
572 op->o_req_ndn = slap_empty_bv;
574 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref );
575 op->o_req_ndn = rndn;
581 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref );
584 case LDAP_REQ_DELETE:
585 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref );
588 case LDAP_REQ_MODRDN:
589 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref );
592 case LDAP_REQ_MODIFY:
593 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref );
596 case LDAP_REQ_COMPARE:
597 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref );
598 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
603 case LDAP_REQ_SEARCH:
604 if ( rs->sr_type == REP_SEARCHREF ) {
605 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
606 ldapinfo_t li = { 0 }, *lip = NULL;
607 struct berval bvuri[ 2 ] = { { 0 } };
609 struct berval *curr = ref,
611 ondn = op->o_req_ndn;
613 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
614 LDAPControl **ctrls = NULL;
616 (void)chaining_control_add( lc, op, &ctrls );
617 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
619 rs->sr_type = REP_SEARCH;
621 sc2.sc_response = ldap_chain_cb_search_response;
623 /* if we parse the URI then by no means
624 * we can cache stuff or reuse connections,
625 * because in back-ldap there's no caching
626 * based on the URI value, which is supposed
627 * to be set once for all (correct?) */
629 for ( ; !BER_BVISNULL( &curr[0] ); curr++ ) {
634 /* parse reference and use
635 * proto://[host][:port]/ only */
636 rc = ldap_url_parse_ext( curr[0].bv_val, &srv );
637 if ( rc != LDAP_URL_SUCCESS ) {
639 rs->sr_err = LDAP_OTHER;
643 /* remove DN essentially because later on
644 * ldap_initialize() will parse the URL
645 * as a comma-separated URL list */
646 save_dn = srv->lud_dn;
648 srv->lud_scope = LDAP_SCOPE_DEFAULT;
649 li.li_uri = ldap_url_desc2str( srv );
650 if ( li.li_uri != NULL ) {
651 ber_str2bv_x( save_dn, 0, 1, &op->o_req_dn,
653 ber_dupbv_x( &op->o_req_ndn, &op->o_req_dn,
657 srv->lud_dn = save_dn;
658 ldap_free_urldesc( srv );
660 if ( li.li_uri == NULL ) {
662 rs->sr_err = LDAP_OTHER;
666 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
668 /* Searches for a ldapinfo in the avl tree */
669 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
670 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
671 (caddr_t)&li, ldap_chain_uri_cmp );
672 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
675 op->o_bd->be_private = (void *)lip;
678 /* if none is found, create a temporary... */
679 rc = ldap_chain_db_init_one( op->o_bd );
683 lip = (ldapinfo_t *)op->o_bd->be_private;
684 lip->li_uri = li.li_uri;
685 lip->li_bvuri = bvuri;
686 rc = ldap_chain_db_open_one( op->o_bd );
688 (void)ldap_chain_db_destroy_one( op->o_bd );
692 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
693 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
694 if ( avl_insert( &lc->lc_lai.lai_tree,
695 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
697 /* someone just inserted another;
698 * don't bother, use this and then
702 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
709 /* FIXME: should we also copy filter and scope?
710 * according to RFC3296, no */
711 rc = lback->bi_op_search( op, rs );
714 ldap_memfree( li.li_uri );
717 op->o_tmpfree( op->o_req_dn.bv_val,
719 op->o_tmpfree( op->o_req_ndn.bv_val,
724 lip->li_bvuri = NULL;
725 (void)ldap_chain_db_close_one( op->o_bd );
726 (void)ldap_chain_db_destroy_one( op->o_bd );
729 if ( rc == LDAP_SUCCESS && rs->sr_err == LDAP_SUCCESS ) {
736 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
737 (void)chaining_control_remove( op, &ctrls );
738 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
741 op->o_req_ndn = ondn;
742 rs->sr_type = REP_SEARCHREF;
745 if ( rc != LDAP_SUCCESS ) {
746 /* couldn't chase any of the referrals */
747 rc = SLAP_CB_CONTINUE;
751 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref );
755 case LDAP_REQ_EXTENDED:
756 rc = ldap_chain_op( op, rs, lback->bi_extended, ref );
757 /* FIXME: ldap_back_extended() by design
758 * doesn't send result; frontend is expected
760 /* FIXME: what aboit chaining? */
761 if ( rc != SLAPD_ABANDON ) {
762 send_ldap_extended( op, rs );
765 sc2.sc_private = LDAP_CH_RES;
769 rc = SLAP_CB_CONTINUE;
779 /* slapd-ldap sent response */
780 assert( sc2.sc_private == LDAP_CH_RES );
784 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
785 if ( sc2.sc_private == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
789 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
790 case LDAP_CHAINING_REQUIRED:
792 op->o_callback = NULL;
793 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
794 "operation cannot be completed without chaining" );
798 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
799 rc = SLAP_CB_CONTINUE;
801 rs->sr_type = sr_type;
802 rs->sr_matched = matched;
804 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
807 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
810 if ( sc2.sc_private == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
811 op->o_callback = NULL;
812 rc = rs->sr_err = slap_map_api2result( rs );
813 send_ldap_result( op, rs );
816 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
818 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
820 rs->sr_type = sr_type;
821 rs->sr_matched = matched;
823 op->o_bd->be_private = private;
830 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
832 ldap_chain_parse_ctrl(
838 str2chain( const char *s )
840 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
841 return LDAP_CHAINING_PREFERRED;
843 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
844 return LDAP_CHAINING_REQUIRED;
846 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
847 return LDAP_REFERRALS_PREFERRED;
849 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
850 return LDAP_REFERRALS_REQUIRED;
855 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
868 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
869 static ConfigDriver chain_cf_gen;
871 static ConfigCfAdd chain_cfadd;
872 static ConfigLDAPadd chain_ldadd;
874 static ConfigTable chaincfg[] = {
875 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
876 { "chain-chaining", "args",
877 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
878 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
879 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
880 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
881 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
882 { "chain-cache-uris", "TRUE/FALSE",
883 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
884 "( OLcfgOvAt:3.2 NAME 'olcCacheURIs' "
885 "DESC 'Enables caching of URIs not present in configuration' "
886 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
887 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
890 static ConfigOCs chainocs[] = {
891 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
893 "NAME 'olcChainConfig' "
894 "DESC 'Chain configuration' "
895 "SUP olcOverlayConfig "
896 "MAY ( olcChainingBehavior "
899 Cft_Overlay, chaincfg, NULL, chain_cfadd },
902 "NAME 'olcChainDatabase' "
903 "DESC 'Chain remote server configuration' "
905 Cft_Misc, chaincfg, chain_ldadd },
910 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
917 AttributeDescription *ad = NULL;
923 if ( p->ce_type != Cft_Overlay
925 || p->ce_bi->bi_cf_ocs != chainocs )
927 return LDAP_CONSTRAINT_VIOLATION;
930 on = (slap_overinst *)p->ce_bi;
931 lc = (ldap_chain_t *)on->on_bi.bi_private;
933 assert( ca->be == NULL );
934 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
936 ca->be->bd_info = (BackendInfo *)on;
938 rc = slap_str2ad( "olcDbURI", &ad, &text );
939 assert( rc == LDAP_SUCCESS );
941 at = attr_find( e->e_attrs, ad );
942 if ( lc->lc_common_li == NULL && at != NULL ) {
943 /* FIXME: we should generate an empty default entry
944 * if none is supplied */
945 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
946 "first underlying database \"%s\" "
947 "cannot contain attribute \"%s\".\n",
948 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
949 rc = LDAP_CONSTRAINT_VIOLATION;
952 } else if ( lc->lc_common_li != NULL && at == NULL ) {
953 /* FIXME: we should generate an empty default entry
954 * if none is supplied */
955 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
956 "subsequent underlying database \"%s\" "
957 "must contain attribute \"%s\".\n",
958 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
959 rc = LDAP_CONSTRAINT_VIOLATION;
963 if ( lc->lc_common_li == NULL ) {
964 rc = ldap_chain_db_init_common( ca->be );
967 rc = ldap_chain_db_init_one( ca->be );
971 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
972 "unable to init %sunderlying database \"%s\".\n",
973 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
974 return LDAP_CONSTRAINT_VIOLATION;
977 li = ca->be->be_private;
979 if ( lc->lc_common_li == NULL ) {
980 lc->lc_common_li = li;
982 } else if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
983 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
985 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
986 "database \"%s\" insert failed.\n",
987 e->e_name.bv_val, 0, 0 );
988 rc = LDAP_CONSTRAINT_VIOLATION;
993 if ( rc != LDAP_SUCCESS ) {
994 (void)ldap_chain_db_destroy_one( ca->be );
1002 typedef struct ldap_chain_cfadd_apply_t {
1008 } ldap_chain_cfadd_apply_t;
1011 ldap_chain_cfadd_apply( void *datum, void *arg )
1013 ldapinfo_t *li = (ldapinfo_t *)datum;
1014 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1018 /* FIXME: should not hardcode "olcDatabase" here */
1019 bv.bv_len = snprintf( lca->ca->msg, sizeof( lca->ca->msg ),
1020 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1021 bv.bv_val = lca->ca->msg;
1023 lca->ca->be->be_private = (void *)li;
1024 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1025 &bv, lback->bi_cf_ocs, &chainocs[1] );
1033 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1035 CfEntryInfo *pe = p->e_private;
1036 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1037 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1038 void *priv = (void *)ca->be->be_private;
1040 if ( lback->bi_cf_ocs ) {
1041 ldap_chain_cfadd_apply_t lca = { 0 };
1049 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1051 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1052 &lca, 1, AVL_INORDER );
1054 ca->be->be_private = priv;
1060 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1062 static slap_verbmasks chaining_mode[] = {
1063 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1064 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1065 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1066 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1071 chain_cf_gen( ConfigArgs *c )
1073 slap_overinst *on = (slap_overinst *)c->bi;
1074 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1078 if ( c->op == SLAP_CONFIG_EMIT ) {
1080 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1082 struct berval resolve = BER_BVNULL,
1083 continuation = BER_BVNULL;
1085 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1089 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1090 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1092 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1094 + STRLENOF( "continuation=" ) + continuation.bv_len;
1095 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1096 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1097 "resolve=%s continuation=%s",
1098 resolve.bv_val, continuation.bv_val );
1100 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1101 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1102 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1103 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1104 " critical", STRLENOF( " critical" ) + 1 );
1105 c->value_bv.bv_len += STRLENOF( " critical" );
1110 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1113 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1122 } else if ( c->op == LDAP_MOD_DELETE ) {
1128 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1138 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1140 char **argv = c->argv;
1142 BerElementBuffer berbuf;
1143 BerElement *ber = (BerElement *)&berbuf;
1147 Operation op = { 0 };
1148 SlapReply rs = { 0 };
1150 lc->lc_chaining_ctrlflag = 0;
1152 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1153 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1154 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1155 if ( resolve == -1 ) {
1156 fprintf( stderr, "%s line %d: "
1157 "illegal <resolve> value %s "
1158 "in \"chain-chaining>\"\n",
1159 c->fname, c->lineno, argv[ 0 ] );
1163 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1164 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1165 if ( continuation == -1 ) {
1166 fprintf( stderr, "%s line %d: "
1167 "illegal <continuation> value %s "
1168 "in \"chain-chaining\"\n",
1169 c->fname, c->lineno, argv[ 0 ] );
1173 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1177 fprintf( stderr, "%s line %d: "
1178 "unknown option in \"chain-chaining\"\n",
1179 c->fname, c->lineno );
1184 if ( resolve != -1 || continuation != -1 ) {
1187 if ( resolve == -1 ) {
1189 resolve = SLAP_CHAINING_DEFAULT;
1192 ber_init2( ber, NULL, LBER_USE_DER );
1194 err = ber_printf( ber, "{e" /* } */, resolve );
1197 fprintf( stderr, "%s line %d: "
1198 "chaining behavior control encoding error!\n",
1199 c->fname, c->lineno );
1203 if ( continuation > -1 ) {
1204 err = ber_printf( ber, "e", continuation );
1207 fprintf( stderr, "%s line %d: "
1208 "chaining behavior control encoding error!\n",
1209 c->fname, c->lineno );
1214 err = ber_printf( ber, /* { */ "N}" );
1217 fprintf( stderr, "%s line %d: "
1218 "chaining behavior control encoding error!\n",
1219 c->fname, c->lineno );
1223 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1224 exit( EXIT_FAILURE );
1228 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1231 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1232 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1234 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1236 fprintf( stderr, "%s line %d: "
1237 "unable to parse chaining control%s%s\n",
1238 c->fname, c->lineno,
1239 rs.sr_text ? ": " : "",
1240 rs.sr_text ? rs.sr_text : "" );
1244 lc->lc_chaining_ctrlflag = op.o_chaining;
1246 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1252 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1255 if ( c->value_int ) {
1256 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1258 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1269 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1275 slap_overinst *on = (slap_overinst *)be->bd_info;
1276 ldap_chain_t *lc = NULL;
1280 if ( lback == NULL ) {
1281 lback = backend_info( "ldap" );
1283 if ( lback == NULL ) {
1288 lc = ch_malloc( sizeof( ldap_chain_t ) );
1289 memset( lc, 0, sizeof( ldap_chain_t ) );
1291 on->on_bi.bi_private = (void *)lc;
1297 ldap_chain_db_config(
1304 slap_overinst *on = (slap_overinst *)be->bd_info;
1305 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1307 int rc = SLAP_CONF_UNKNOWN;
1309 if ( lc->lc_common_li == NULL ) {
1310 ldap_chain_db_init_common( be );
1311 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1314 /* Something for the chain database? */
1315 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1316 char *save_argv0 = argv[ 0 ];
1317 BackendInfo *bd_info = bd_info;
1318 void *be_private = be->be_private;
1319 ConfigOCs *be_cf_ocs = be->be_cf_ocs;
1322 argv[ 0 ] += STRLENOF( "chain-" );
1324 /* TODO: create a new structure and, after parsing the URI,
1325 * put it in the lc->lc_lai tree */
1326 if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
1327 rc = ldap_chain_db_init_one( be );
1329 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1330 "underlying slapd-ldap initialization failed\n.",
1334 lc->lc_cfg_li = be->be_private;
1338 be->bd_info = lback;
1339 be->be_private = (void *)lc->lc_cfg_li;
1340 be->be_cf_ocs = lback->bi_cf_ocs;
1342 rc = config_generic_wrapper( be, fname, lineno, argc, argv );
1344 argv[ 0 ] = save_argv0;
1345 be->be_cf_ocs = be_cf_ocs;
1346 be->be_private = be_private;
1347 be->bd_info = bd_info;
1355 db.be_private = (void *)lc->lc_cfg_li;
1356 ldap_chain_db_destroy_one( &db );
1357 lc->lc_cfg_li = NULL;
1360 if ( lc->lc_cfg_li->li_bvuri == NULL
1361 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1362 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1364 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1365 "no URI list allowed in slapo-chain.\n",
1368 goto private_destroy;
1371 if ( avl_insert( &lc->lc_lai.lai_tree,
1372 (caddr_t)lc->lc_cfg_li,
1373 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1375 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1376 "duplicate URI in slapo-chain.\n",
1379 goto private_destroy;
1396 typedef struct ldap_chain_db_apply_t {
1399 } ldap_chain_db_apply_t;
1402 ldap_chain_db_apply( void *datum, void *arg )
1404 ldapinfo_t *li = (ldapinfo_t *)datum;
1405 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1407 lca->be->be_private = (void *)li;
1409 return lca->func( lca->be );
1418 slap_overinst *on = (slap_overinst *)be->bd_info;
1419 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1424 BI_db_func *func = (&lback->bi_db_open)[ which ];
1426 if ( func != NULL && lc->lc_common_li != NULL ) {
1430 db.be_private = lc->lc_common_li;
1438 if ( lc->lc_lai.lai_tree != NULL ) {
1439 ldap_chain_db_apply_t lca;
1444 rc = avl_apply( lc->lc_lai.lai_tree,
1445 ldap_chain_db_apply, (void *)&lca,
1446 1, AVL_INORDER ) != AVL_NOMORE;
1458 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1461 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1465 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1467 /* FIXME: right now slapd-ldap has no open function;
1468 * in case one is introduced, this needs be fixed */
1470 return ldap_chain_db_func( be, db_open );
1474 ldap_chain_db_close(
1477 return ldap_chain_db_func( be, db_close );
1481 ldap_chain_db_destroy(
1484 slap_overinst *on = (slap_overinst *) be->bd_info;
1485 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1489 rc = ldap_chain_db_func( be, db_destroy );
1492 avl_free( lc->lc_lai.lai_tree, NULL );
1500 ldap_chain_db_init_common(
1503 slap_overinst *on = (slap_overinst *)be->bd_info;
1504 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1506 BackendInfo *bi = be->bd_info;
1510 assert( lc->lc_common_li == NULL );
1512 be->bd_info = lback;
1513 be->be_private = NULL;
1514 t = lback->bi_db_init( be );
1524 ldap_chain_db_init_one(
1527 slap_overinst *on = (slap_overinst *)be->bd_info;
1528 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1530 BackendInfo *bi = be->bd_info;
1535 be->bd_info = lback;
1536 be->be_private = NULL;
1537 t = lback->bi_db_init( be );
1541 li = (ldapinfo_t *)be->be_private;
1543 /* copy common data */
1544 li->li_nretries = lc->lc_common_li->li_nretries;
1545 li->li_flags = lc->lc_common_li->li_flags;
1546 li->li_version = lc->lc_common_li->li_version;
1547 for ( t = 0; t < LDAP_BACK_OP_LAST; t++ ) {
1548 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
1555 typedef struct ldap_chain_conn_apply_t {
1558 } ldap_chain_conn_apply_t;
1561 ldap_chain_conn_apply( void *datum, void *arg )
1563 ldapinfo_t *li = (ldapinfo_t *)datum;
1564 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
1566 lca->be->be_private = (void *)li;
1568 return lback->bi_connection_destroy( lca->be, lca->conn );
1572 ldap_chain_connection_destroy(
1577 slap_overinst *on = (slap_overinst *) be->bd_info;
1578 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1579 void *private = be->be_private;
1580 ldap_chain_conn_apply_t lca;
1583 be->be_private = NULL;
1586 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
1587 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
1588 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
1589 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
1590 be->be_private = private;
1595 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1597 ldap_chain_parse_ctrl(
1607 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
1608 rs->sr_text = "Chaining behavior control specified multiple times";
1609 return LDAP_PROTOCOL_ERROR;
1612 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
1613 rs->sr_text = "Chaining behavior control specified with pagedResults control";
1614 return LDAP_PROTOCOL_ERROR;
1617 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
1618 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
1623 /* Parse the control value
1624 * ChainingBehavior ::= SEQUENCE {
1625 * resolveBehavior Behavior OPTIONAL,
1626 * continuationBehavior Behavior OPTIONAL }
1628 * Behavior :: = ENUMERATED {
1629 * chainingPreferred (0),
1630 * chainingRequired (1),
1631 * referralsPreferred (2),
1632 * referralsRequired (3) }
1635 ber = ber_init( &ctrl->ldctl_value );
1637 rs->sr_text = "internal error";
1641 tag = ber_scanf( ber, "{e" /* } */, &behavior );
1642 /* FIXME: since the whole SEQUENCE is optional,
1643 * should we accept no enumerations at all? */
1644 if ( tag != LBER_ENUMERATED ) {
1645 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
1646 return LDAP_PROTOCOL_ERROR;
1649 switch ( behavior ) {
1650 case LDAP_CHAINING_PREFERRED:
1651 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
1654 case LDAP_CHAINING_REQUIRED:
1655 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
1658 case LDAP_REFERRALS_PREFERRED:
1659 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
1662 case LDAP_REFERRALS_REQUIRED:
1663 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
1667 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
1668 return LDAP_PROTOCOL_ERROR;
1671 tag = ber_peek_tag( ber, &len );
1672 if ( tag == LBER_ENUMERATED ) {
1673 tag = ber_scanf( ber, "e", &behavior );
1674 if ( tag == LBER_ERROR ) {
1675 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
1676 return LDAP_PROTOCOL_ERROR;
1680 if ( tag == LBER_DEFAULT ) {
1681 mode |= SLAP_CH_CONTINUATION_DEFAULT;
1684 switch ( behavior ) {
1685 case LDAP_CHAINING_PREFERRED:
1686 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
1689 case LDAP_CHAINING_REQUIRED:
1690 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
1693 case LDAP_REFERRALS_PREFERRED:
1694 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
1697 case LDAP_REFERRALS_REQUIRED:
1698 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
1702 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
1703 return LDAP_PROTOCOL_ERROR;
1707 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
1708 rs->sr_text = "Chaining behavior control: decoding error";
1709 return LDAP_PROTOCOL_ERROR;
1712 (void) ber_free( ber, 1 );
1715 op->o_chaining = mode | ( ctrl->ldctl_iscritical
1716 ? SLAP_CONTROL_CRITICAL
1717 : SLAP_CONTROL_NONCRITICAL );
1719 return LDAP_SUCCESS;
1721 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1723 static slap_overinst ldapchain;
1730 /* Make sure we don't exceed the bits reserved for userland */
1731 config_check_userland( CH_LAST );
1733 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1734 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
1735 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
1736 ldap_chain_parse_ctrl, &sc_chainingBehavior );
1737 if ( rc != LDAP_SUCCESS ) {
1738 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1739 "unable to register chaining behavior control: %d\n",
1743 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1745 ldapchain.on_bi.bi_type = "chain";
1746 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
1747 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
1748 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
1749 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
1750 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
1752 /* ... otherwise the underlying backend's function would be called,
1753 * likely passing an invalid entry; on the contrary, the requested
1754 * operational attributes should have been returned while chasing
1755 * the referrals. This all in all is a bit messy, because part
1756 * of the operational attributes are generated by the backend;
1757 * part by the frontend; back-ldap should receive all the available
1758 * ones from the remote server, but then, on its own, it strips those
1759 * it assumes will be (re)generated by the frontend (e.g.
1760 * subschemaSubentry.) */
1761 ldapchain.on_bi.bi_operational = ldap_chain_operational;
1763 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
1765 ldapchain.on_response = ldap_chain_response;
1767 ldapchain.on_bi.bi_cf_ocs = chainocs;
1769 rc = config_register_schema( chaincfg, chainocs );
1774 return overlay_register( &ldapchain );