1 /* chain.c - chain LDAP operations */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2003-2011 The OpenLDAP Foundation.
6 * Portions Copyright 2003 Howard Chu.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This work was initially developed by the Howard Chu for inclusion
19 * in OpenLDAP Software.
20 * This work was subsequently modified by Pierangelo Masarati.
27 #include <ac/string.h>
28 #include <ac/socket.h>
32 #include "back-ldap.h"
35 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
36 #define SLAP_CHAINING_DEFAULT LDAP_CHAINING_PREFERRED
37 #define SLAP_CH_RESOLVE_SHIFT SLAP_CONTROL_SHIFT
38 #define SLAP_CH_RESOLVE_MASK (0x3 << SLAP_CH_RESOLVE_SHIFT)
39 #define SLAP_CH_RESOLVE_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
40 #define SLAP_CH_RESOLVE_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
41 #define SLAP_CH_RESOLVE_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_RESOLVE_SHIFT)
42 #define SLAP_CH_RESOLVE_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_RESOLVE_SHIFT)
43 #define SLAP_CH_RESOLVE_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_RESOLVE_SHIFT)
44 #define SLAP_CH_CONTINUATION_SHIFT (SLAP_CH_RESOLVE_SHIFT + 2)
45 #define SLAP_CH_CONTINUATION_MASK (0x3 << SLAP_CH_CONTINUATION_SHIFT)
46 #define SLAP_CH_CONTINUATION_CHAINING_PREFERRED (LDAP_CHAINING_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
47 #define SLAP_CH_CONTINUATION_CHAINING_REQUIRED (LDAP_CHAINING_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
48 #define SLAP_CH_CONTINUATION_REFERRALS_PREFERRED (LDAP_REFERRALS_PREFERRED << SLAP_CH_CONTINUATION_SHIFT)
49 #define SLAP_CH_CONTINUATION_REFERRALS_REQUIRED (LDAP_REFERRALS_REQUIRED << SLAP_CH_CONTINUATION_SHIFT)
50 #define SLAP_CH_CONTINUATION_DEFAULT (SLAP_CHAINING_DEFAULT << SLAP_CH_CONTINUATION_SHIFT)
52 #define o_chaining o_ctrlflag[sc_chainingBehavior]
53 #define get_chaining(op) ((op)->o_chaining & SLAP_CONTROL_MASK)
54 #define get_chainingBehavior(op) ((op)->o_chaining & (SLAP_CH_RESOLVE_MASK|SLAP_CH_CONTINUATION_MASK))
55 #define get_resolveBehavior(op) ((op)->o_chaining & SLAP_CH_RESOLVE_MASK)
56 #define get_continuationBehavior(op) ((op)->o_chaining & SLAP_CH_CONTINUATION_MASK)
58 static int sc_chainingBehavior;
59 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
65 } ldap_chain_status_t;
67 static BackendInfo *lback;
69 typedef struct ldap_chain_t {
71 * A "template" ldapinfo_t gets all common configuration items;
72 * then, for each configured URI, an entry is created in the tree;
73 * all the specific configuration items get in the current URI
76 * Then, for each referral, extract the URI and lookup the
77 * related structure. If configured to do so, allow URIs
78 * not found in the structure to create a temporary one
79 * that chains anonymously; maybe it can also be added to
80 * the tree? Should be all configurable.
83 /* "common" configuration info (anything occurring before an "uri") */
84 ldapinfo_t *lc_common_li;
86 /* current configuration info */
87 ldapinfo_t *lc_cfg_li;
89 /* tree of configured[/generated?] "uri" info */
90 ldap_avl_info_t lc_lai;
92 /* max depth in nested referrals chaining */
96 #define LDAP_CHAIN_F_NONE (0x00U)
97 #define LDAP_CHAIN_F_CHAINING (0x01U)
98 #define LDAP_CHAIN_F_CACHE_URI (0x02U)
99 #define LDAP_CHAIN_F_RETURN_ERR (0x04U)
101 #define LDAP_CHAIN_ISSET(lc, f) ( ( (lc)->lc_flags & (f) ) == (f) )
102 #define LDAP_CHAIN_CHAINING( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CHAINING )
103 #define LDAP_CHAIN_CACHE_URI( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_CACHE_URI )
104 #define LDAP_CHAIN_RETURN_ERR( lc ) LDAP_CHAIN_ISSET( (lc), LDAP_CHAIN_F_RETURN_ERR )
106 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
107 LDAPControl lc_chaining_ctrl;
108 char lc_chaining_ctrlflag;
109 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
112 static int ldap_chain_db_init_common( BackendDB *be );
113 static int ldap_chain_db_init_one( BackendDB *be );
114 static int ldap_chain_db_open_one( BackendDB *be );
115 #define ldap_chain_db_close_one(be) (0)
116 #define ldap_chain_db_destroy_one(be, rs) (lback)->bi_db_destroy( (be), (rs) )
118 typedef struct ldap_chain_cb_t {
119 ldap_chain_status_t lb_status;
140 static slap_overinst ldapchain;
142 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
144 chaining_control_add(
147 LDAPControl ***oldctrlsp )
149 LDAPControl **ctrls = NULL;
152 *oldctrlsp = op->o_ctrls;
154 /* default chaining control not defined */
155 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
159 /* already present */
160 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
164 /* FIXME: check other incompatibilities */
166 /* add to other controls */
168 for ( c = 0; op->o_ctrls[ c ]; c++ )
172 ctrls = ch_calloc( sizeof( LDAPControl *), c + 2 );
173 ctrls[ 0 ] = &lc->lc_chaining_ctrl;
175 for ( c = 0; op->o_ctrls[ c ]; c++ ) {
176 ctrls[ c + 1 ] = op->o_ctrls[ c ];
179 ctrls[ c + 1 ] = NULL;
183 op->o_chaining = lc->lc_chaining_ctrlflag;
189 chaining_control_remove(
191 LDAPControl ***oldctrlsp )
193 LDAPControl **oldctrls = *oldctrlsp;
195 /* we assume that the first control is the chaining control
196 * added by the chain overlay, so it's the only one we explicitly
198 if ( op->o_ctrls != oldctrls ) {
199 assert( op->o_ctrls != NULL );
200 assert( op->o_ctrls[ 0 ] != NULL );
205 op->o_ctrls = oldctrls;
212 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
215 ldap_chain_uri_cmp( const void *c1, const void *c2 )
217 const ldapinfo_t *li1 = (const ldapinfo_t *)c1;
218 const ldapinfo_t *li2 = (const ldapinfo_t *)c2;
220 assert( li1->li_bvuri != NULL );
221 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
222 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
224 assert( li2->li_bvuri != NULL );
225 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
226 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
228 return ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] );
232 ldap_chain_uri_dup( void *c1, void *c2 )
234 ldapinfo_t *li1 = (ldapinfo_t *)c1;
235 ldapinfo_t *li2 = (ldapinfo_t *)c2;
237 assert( li1->li_bvuri != NULL );
238 assert( !BER_BVISNULL( &li1->li_bvuri[ 0 ] ) );
239 assert( BER_BVISNULL( &li1->li_bvuri[ 1 ] ) );
241 assert( li2->li_bvuri != NULL );
242 assert( !BER_BVISNULL( &li2->li_bvuri[ 0 ] ) );
243 assert( BER_BVISNULL( &li2->li_bvuri[ 1 ] ) );
245 if ( ber_bvcmp( &li1->li_bvuri[ 0 ], &li2->li_bvuri[ 0 ] ) == 0 ) {
253 * Search specific response that strips entryDN from entries
256 ldap_chain_cb_search_response( Operation *op, SlapReply *rs )
258 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
260 assert( op->o_tag == LDAP_REQ_SEARCH );
262 /* if in error, don't proceed any further */
263 if ( lb->lb_status == LDAP_CH_ERR ) {
267 if ( rs->sr_type == REP_SEARCH ) {
268 Attribute **ap = &rs->sr_entry->e_attrs;
270 for ( ; *ap != NULL; ap = &(*ap)->a_next ) {
271 /* will be generated later by frontend
272 * (a cleaner solution would be that
273 * the frontend checks if it already exists */
274 if ( ad_cmp( (*ap)->a_desc, slap_schema.si_ad_entryDN ) == 0 )
281 /* there SHOULD be one only! */
286 /* tell the frontend not to add generated
287 * operational attributes */
288 rs->sr_flags |= REP_NO_OPERATIONALS;
290 return SLAP_CB_CONTINUE;
292 } else if ( rs->sr_type == REP_SEARCHREF ) {
293 /* if we get it here, it means the library was unable
294 * to chase the referral... */
295 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
296 rs->sr_err = ldap_chain_search( op, rs, rs->sr_ref, lb->lb_depth );
299 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
300 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
301 switch ( get_continuationBehavior( op ) ) {
302 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
303 lb->lb_status = LDAP_CH_ERR;
304 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
310 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
311 return SLAP_CB_CONTINUE;
313 } else if ( rs->sr_type == REP_RESULT ) {
314 if ( rs->sr_err == LDAP_REFERRAL
315 && lb->lb_depth < lb->lb_lc->lc_max_depth
316 && rs->sr_ref != NULL )
318 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
321 /* back-ldap tried to send result */
322 lb->lb_status = LDAP_CH_RES;
329 * Dummy response that simply traces if back-ldap tried to send
330 * anything to the client
333 ldap_chain_cb_response( Operation *op, SlapReply *rs )
335 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
337 /* if in error, don't proceed any further */
338 if ( lb->lb_status == LDAP_CH_ERR ) {
342 if ( rs->sr_type == REP_RESULT ) {
344 switch ( rs->sr_err ) {
345 case LDAP_COMPARE_TRUE:
346 case LDAP_COMPARE_FALSE:
347 if ( op->o_tag != LDAP_REQ_COMPARE ) {
353 lb->lb_status = LDAP_CH_RES;
357 if ( lb->lb_depth < lb->lb_lc->lc_max_depth && rs->sr_ref != NULL ) {
358 rs->sr_err = ldap_chain_op( op, rs, lb->lb_op_f, rs->sr_ref, lb->lb_depth );
362 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
363 if ( get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
364 switch ( get_continuationBehavior( op ) ) {
365 case SLAP_CH_RESOLVE_CHAINING_REQUIRED:
366 lb->lb_status = LDAP_CH_ERR;
367 return rs->sr_err = LDAP_X_CANNOT_CHAIN;
373 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
380 } else if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH )
382 /* strip the entryDN attribute, but keep returning results */
383 (void)ldap_chain_cb_search_response( op, rs );
386 return SLAP_CB_CONTINUE;
397 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
398 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
399 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
400 struct berval odn = op->o_req_dn,
401 ondn = op->o_req_ndn;
402 ldapinfo_t li = { 0 }, *lip = NULL;
403 struct berval bvuri[ 2 ] = { { 0 } };
405 /* NOTE: returned if ref is empty... */
409 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
410 LDAPControl **ctrls = NULL;
412 (void)chaining_control_add( lc, op, &ctrls );
413 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
417 for ( ; !BER_BVISNULL( ref ); ref++ ) {
418 SlapReply rs2 = { 0 };
419 LDAPURLDesc *srv = NULL;
420 req_search_s save_oq_search = op->oq_search,
421 tmp_oq_search = { 0 };
422 struct berval dn = BER_BVNULL,
429 /* We're setting the URI of the first referral;
430 * what if there are more?
436 If the client wishes to progress the operation, it MUST follow the
437 referral by contacting one of the supported services. If multiple
438 URIs are present, the client assumes that any supported URI may be
439 used to progress the operation.
441 * so we actually need to follow exactly one,
442 * and we can assume any is fine.
445 /* parse reference and use
446 * proto://[host][:port]/ only */
447 rc = ldap_url_parse_ext( ref->bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
448 if ( rc != LDAP_URL_SUCCESS ) {
449 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: unable to parse ref=\"%s\"\n",
450 op->o_log_prefix, ref->bv_val, 0 );
457 if ( op->o_tag == LDAP_REQ_SEARCH ) {
458 if ( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
459 /* RFC 4511: if scope is present, use it */
460 tmp_oq_search.rs_scope = srv->lud_scope;
463 /* RFC 4511: if scope is absent, use original */
464 tmp_oq_search.rs_scope = op->ors_scope;
469 srv->lud_scope = LDAP_SCOPE_DEFAULT;
470 dn.bv_val = srv->lud_dn;
471 filter = srv->lud_filter;
474 if ( srv->lud_dn == NULL || srv->lud_dn[0] == '\0' ) {
475 if ( srv->lud_dn == NULL ) {
480 ber_str2bv( srv->lud_dn, 0, 0, &dn );
481 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
482 if ( rc == LDAP_SUCCESS ) {
483 /* remove DN essentially because later on
484 * ldap_initialize() will parse the URL
485 * as a comma-separated URL list */
492 if ( rc == LDAP_SUCCESS && op->o_tag == LDAP_REQ_SEARCH ) {
494 if ( srv->lud_filter != NULL
495 && srv->lud_filter[0] != '\0'
496 && strcasecmp( srv->lud_filter, "(objectClass=*)" ) != 0 )
498 /* RFC 4511: if filter is present, use it;
499 * otherwise, use original */
500 tmp_oq_search.rs_filter = str2filter_x( op, srv->lud_filter );
501 if ( tmp_oq_search.rs_filter != NULL ) {
502 filter2bv_x( op, tmp_oq_search.rs_filter, &tmp_oq_search.rs_filterstr );
505 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\": unable to parse filter=\"%s\"\n",
506 op->o_log_prefix, ref->bv_val, srv->lud_filter );
511 srv->lud_filter = NULL;
513 if ( rc == LDAP_SUCCESS ) {
514 li.li_uri = ldap_url_desc2str( srv );
517 srv->lud_dn = dn.bv_val;
518 srv->lud_filter = filter;
519 ldap_free_urldesc( srv );
521 if ( rc != LDAP_SUCCESS ) {
527 if ( li.li_uri == NULL ) {
528 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to reconstruct URI\n",
529 op->o_log_prefix, ref->bv_val, 0 );
533 goto further_cleanup;
536 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" -> \"%s\"\n",
537 op->o_log_prefix, ref->bv_val, li.li_uri );
542 if ( op->o_tag == LDAP_REQ_SEARCH ) {
543 op->ors_scope = tmp_oq_search.rs_scope;
544 if ( tmp_oq_search.rs_filter != NULL ) {
545 op->ors_filter = tmp_oq_search.rs_filter;
546 op->ors_filterstr = tmp_oq_search.rs_filterstr;
550 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
552 /* Searches for a ldapinfo in the avl tree */
553 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
554 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
555 (caddr_t)&li, ldap_chain_uri_cmp );
556 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
559 op->o_bd->be_private = (void *)lip;
561 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\": URI=\"%s\" found in cache\n",
562 op->o_log_prefix, ref->bv_val, li.li_uri );
565 rc = ldap_chain_db_init_one( op->o_bd );
567 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to init back-ldap for URI=\"%s\"\n",
568 op->o_log_prefix, ref->bv_val, li.li_uri );
571 lip = (ldapinfo_t *)op->o_bd->be_private;
572 lip->li_uri = li.li_uri;
573 lip->li_bvuri = bvuri;
574 rc = ldap_chain_db_open_one( op->o_bd );
576 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" unable to open back-ldap for URI=\"%s\"\n",
577 op->o_log_prefix, ref->bv_val, li.li_uri );
579 lip->li_bvuri = NULL;
580 (void)ldap_chain_db_destroy_one( op->o_bd, NULL);
584 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
585 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
586 if ( avl_insert( &lc->lc_lai.lai_tree,
587 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
589 /* someone just inserted another;
590 * don't bother, use this and then
594 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
600 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_op: ref=\"%s\" %s\n",
601 op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
605 lb->lb_depth = depth + 1;
607 rc = op_f( op, &rs2 );
609 /* note the first error */
610 if ( first_rc == -1 ) {
615 ldap_memfree( li.li_uri );
620 lip->li_bvuri = NULL;
621 (void)ldap_chain_db_close_one( op->o_bd );
622 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
627 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
628 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
631 if ( op->o_tag == LDAP_REQ_SEARCH ) {
632 if ( tmp_oq_search.rs_filter != NULL ) {
633 filter_free_x( op, tmp_oq_search.rs_filter, 1 );
636 if ( !BER_BVISNULL( &tmp_oq_search.rs_filterstr ) ) {
637 slap_sl_free( tmp_oq_search.rs_filterstr.bv_val, op->o_tmpmemctx );
640 op->oq_search = save_oq_search;
643 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
652 op->o_req_ndn = ondn;
654 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
655 (void)chaining_control_remove( op, &ctrls );
656 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
658 if ( rc != LDAP_SUCCESS && first_rc > 0 ) {
673 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
674 ldap_chain_cb_t *lb = (ldap_chain_cb_t *)op->o_callback->sc_private;
675 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
676 ldapinfo_t li = { 0 }, *lip = NULL;
677 struct berval bvuri[ 2 ] = { { 0 } };
679 struct berval odn = op->o_req_dn,
680 ondn = op->o_req_ndn;
681 Entry *save_entry = rs->sr_entry;
682 slap_mask_t save_flags = rs->sr_flags;
687 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
688 LDAPControl **ctrls = NULL;
690 (void)chaining_control_add( lc, op, &ctrls );
691 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
693 assert( rs->sr_type == REP_SEARCHREF );
695 rs->sr_type = REP_SEARCH;
697 /* if we parse the URI then by no means
698 * we can cache stuff or reuse connections,
699 * because in back-ldap there's no caching
700 * based on the URI value, which is supposed
701 * to be set once for all (correct?) */
703 for ( ; !BER_BVISNULL( &ref[0] ); ref++ ) {
704 SlapReply rs2 = { REP_RESULT };
706 req_search_s save_oq_search = op->oq_search,
707 tmp_oq_search = { 0 };
715 /* parse reference and use
716 * proto://[host][:port]/ only */
717 rc = ldap_url_parse_ext( ref[0].bv_val, &srv, LDAP_PVT_URL_PARSE_NONE );
718 if ( rc != LDAP_URL_SUCCESS ) {
719 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: unable to parse ref=\"%s\"\n",
720 op->o_log_prefix, ref->bv_val, 0 );
723 rs->sr_err = LDAP_OTHER;
727 if ( srv->lud_scope != LDAP_SCOPE_DEFAULT ) {
728 /* RFC 4511: if scope is present, use it */
729 tmp_oq_search.rs_scope = srv->lud_scope;
732 /* RFC 4511: if scope is absent, use original */
733 /* Section 4.5.3: if scope is onelevel, use base */
734 if ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
735 tmp_oq_search.rs_scope = LDAP_SCOPE_BASE;
737 tmp_oq_search.rs_scope = op->ors_scope;
741 srv->lud_scope = LDAP_SCOPE_DEFAULT;
742 dn.bv_val = srv->lud_dn;
743 filter = srv->lud_filter;
746 if ( srv->lud_dn == NULL || srv->lud_dn[0] == '\0' ) {
747 if ( srv->lud_dn == NULL ) {
751 if ( save_entry != NULL ) {
752 /* use the "right" DN, if available */
753 pdn = save_entry->e_name;
754 ndn = save_entry->e_nname;
755 } /* else leave the original req DN in place, if any RFC 4511 */
758 /* RFC 4511: if DN is present, use it */
759 ber_str2bv( srv->lud_dn, 0, 0, &dn );
760 rc = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
761 if ( rc == LDAP_SUCCESS ) {
762 /* remove DN essentially because later on
763 * ldap_initialize() will parse the URL
764 * as a comma-separated URL list */
771 if ( rc == LDAP_SUCCESS ) {
773 if ( srv->lud_filter != NULL
774 && srv->lud_filter[0] != '\0'
775 && strcasecmp( srv->lud_filter, "(objectClass=*)" ) != 0 )
777 /* RFC 4511: if filter is present, use it;
778 * otherwise, use original */
779 tmp_oq_search.rs_filter = str2filter_x( op, srv->lud_filter );
780 if ( tmp_oq_search.rs_filter != NULL ) {
781 filter2bv_x( op, tmp_oq_search.rs_filter, &tmp_oq_search.rs_filterstr );
784 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\": unable to parse filter=\"%s\"\n",
785 op->o_log_prefix, ref->bv_val, srv->lud_filter );
790 srv->lud_filter = NULL;
792 if ( rc == LDAP_SUCCESS ) {
793 li.li_uri = ldap_url_desc2str( srv );
796 srv->lud_dn = dn.bv_val;
797 srv->lud_filter = filter;
798 ldap_free_urldesc( srv );
800 if ( rc != LDAP_SUCCESS || li.li_uri == NULL ) {
801 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to reconstruct URI\n",
802 op->o_log_prefix, ref->bv_val, 0 );
806 goto further_cleanup;
809 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" -> \"%s\"\n",
810 op->o_log_prefix, ref->bv_val, li.li_uri );
814 op->ors_scope = tmp_oq_search.rs_scope;
815 if ( tmp_oq_search.rs_filter != NULL ) {
816 op->ors_filter = tmp_oq_search.rs_filter;
817 op->ors_filterstr = tmp_oq_search.rs_filterstr;
820 ber_str2bv( li.li_uri, 0, 0, &li.li_bvuri[ 0 ] );
822 /* Searches for a ldapinfo in the avl tree */
823 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
824 lip = (ldapinfo_t *)avl_find( lc->lc_lai.lai_tree,
825 (caddr_t)&li, ldap_chain_uri_cmp );
826 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
829 op->o_bd->be_private = (void *)lip;
831 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\": URI=\"%s\" found in cache\n",
832 op->o_log_prefix, ref->bv_val, li.li_uri );
835 /* if none is found, create a temporary... */
836 rc = ldap_chain_db_init_one( op->o_bd );
838 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to init back-ldap for URI=\"%s\"\n",
839 op->o_log_prefix, ref->bv_val, li.li_uri );
842 lip = (ldapinfo_t *)op->o_bd->be_private;
843 lip->li_uri = li.li_uri;
844 lip->li_bvuri = bvuri;
845 rc = ldap_chain_db_open_one( op->o_bd );
847 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" unable to open back-ldap for URI=\"%s\"\n",
848 op->o_log_prefix, ref->bv_val, li.li_uri );
850 lip->li_bvuri = NULL;
851 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
855 if ( LDAP_CHAIN_CACHE_URI( lc ) ) {
856 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
857 if ( avl_insert( &lc->lc_lai.lai_tree,
858 (caddr_t)lip, ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
860 /* someone just inserted another;
861 * don't bother, use this and then
865 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
871 Debug( LDAP_DEBUG_TRACE, "%s ldap_chain_search: ref=\"%s\" %s\n",
872 op->o_log_prefix, ref->bv_val, temporary ? "temporary" : "caching" );
875 lb->lb_op_f = lback->bi_op_search;
876 lb->lb_depth = depth + 1;
878 /* FIXME: should we also copy filter and scope?
879 * according to RFC3296, no */
880 rc = lback->bi_op_search( op, &rs2 );
881 if ( first_rc == -1 ) {
886 ldap_memfree( li.li_uri );
891 lip->li_bvuri = NULL;
892 (void)ldap_chain_db_close_one( op->o_bd );
893 (void)ldap_chain_db_destroy_one( op->o_bd, NULL );
898 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
899 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
903 op->o_req_ndn = ondn;
905 if ( tmp_oq_search.rs_filter != NULL ) {
906 filter_free_x( op, tmp_oq_search.rs_filter, 1 );
909 if ( !BER_BVISNULL( &tmp_oq_search.rs_filterstr ) ) {
910 slap_sl_free( tmp_oq_search.rs_filterstr.bv_val, op->o_tmpmemctx );
913 op->oq_search = save_oq_search;
915 if ( rc == LDAP_SUCCESS && rs2.sr_err == LDAP_SUCCESS ) {
923 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
924 (void)chaining_control_remove( op, &ctrls );
925 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
928 op->o_req_ndn = ondn;
929 rs->sr_type = REP_SEARCHREF;
930 rs->sr_entry = save_entry;
931 rs->sr_flags = save_flags;
933 if ( rc != LDAP_SUCCESS ) {
934 /* couldn't chase any of the referrals */
935 if ( first_rc != -1 ) {
939 rc = SLAP_CB_CONTINUE;
947 ldap_chain_response( Operation *op, SlapReply *rs )
949 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
950 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
951 BackendDB db, *bd = op->o_bd;
952 ldap_chain_cb_t lb = { 0 };
953 slap_callback *sc = op->o_callback,
956 const char *text = NULL;
959 struct berval ndn = op->o_ndn;
961 int sr_err = rs->sr_err;
962 slap_reply_t sr_type = rs->sr_type;
963 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
964 slap_mask_t chain_mask = 0;
965 ber_len_t chain_shift = 0;
966 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
968 if ( rs->sr_err != LDAP_REFERRAL && rs->sr_type != REP_SEARCHREF ) {
969 return SLAP_CB_CONTINUE;
972 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
973 if ( rs->sr_err == LDAP_REFERRAL && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
974 switch ( get_resolveBehavior( op ) ) {
975 case SLAP_CH_RESOLVE_REFERRALS_PREFERRED:
976 case SLAP_CH_RESOLVE_REFERRALS_REQUIRED:
977 return SLAP_CB_CONTINUE;
980 chain_mask = SLAP_CH_RESOLVE_MASK;
981 chain_shift = SLAP_CH_RESOLVE_SHIFT;
985 } else if ( rs->sr_type == REP_SEARCHREF && get_chaining( op ) > SLAP_CONTROL_IGNORED ) {
986 switch ( get_continuationBehavior( op ) ) {
987 case SLAP_CH_CONTINUATION_REFERRALS_PREFERRED:
988 case SLAP_CH_CONTINUATION_REFERRALS_REQUIRED:
989 return SLAP_CB_CONTINUE;
992 chain_mask = SLAP_CH_CONTINUATION_MASK;
993 chain_shift = SLAP_CH_CONTINUATION_SHIFT;
997 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1000 * TODO: add checks on who/when chain operations; e.g.:
1001 * a) what identities are authorized
1002 * b) what request DN (e.g. only chain requests rooted at <DN>)
1003 * c) what referral URIs
1004 * d) what protocol scheme (e.g. only ldaps://)
1009 SLAP_DBFLAGS( &db ) &= ~SLAP_DBFLAG_MONITORING;
1014 matched = rs->sr_matched;
1015 rs->sr_matched = NULL;
1019 /* we need this to know if back-ldap returned any result */
1021 sc2.sc_next = sc->sc_next;
1022 sc2.sc_private = &lb;
1023 sc2.sc_response = ldap_chain_cb_response;
1024 op->o_callback = &sc2;
1026 /* Chaining can be performed by a privileged user on behalf
1027 * of normal users, using the ProxyAuthz control, by exploiting
1028 * the identity assertion feature of back-ldap; see idassert-*
1029 * directives in slapd-ldap(5).
1031 * FIXME: the idassert-authcDN is one, will it be fine regardless
1032 * of the URI we obtain from the referral?
1035 switch ( op->o_tag ) {
1036 case LDAP_REQ_BIND: {
1037 struct berval rndn = op->o_req_ndn;
1038 Connection *conn = op->o_conn;
1040 /* FIXME: can we really get a referral for binds? */
1041 op->o_req_ndn = slap_empty_bv;
1043 rc = ldap_chain_op( op, rs, lback->bi_op_bind, ref, 0 );
1044 op->o_req_ndn = rndn;
1050 rc = ldap_chain_op( op, rs, lback->bi_op_add, ref, 0 );
1053 case LDAP_REQ_DELETE:
1054 rc = ldap_chain_op( op, rs, lback->bi_op_delete, ref, 0 );
1057 case LDAP_REQ_MODRDN:
1058 rc = ldap_chain_op( op, rs, lback->bi_op_modrdn, ref, 0 );
1061 case LDAP_REQ_MODIFY:
1062 rc = ldap_chain_op( op, rs, lback->bi_op_modify, ref, 0 );
1065 case LDAP_REQ_COMPARE:
1066 rc = ldap_chain_op( op, rs, lback->bi_op_compare, ref, 0 );
1067 if ( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) {
1072 case LDAP_REQ_SEARCH:
1073 if ( rs->sr_type == REP_SEARCHREF ) {
1074 sc2.sc_response = ldap_chain_cb_search_response;
1075 rc = ldap_chain_search( op, rs, ref, 0 );
1078 /* we might get here before any database actually
1079 * performed a search; in those cases, we need
1080 * to check limits, to make sure safe defaults
1082 if ( op->ors_limit != NULL || limits_check( op, rs ) == 0 ) {
1083 rc = ldap_chain_op( op, rs, lback->bi_op_search, ref, 0 );
1086 rc = SLAP_CB_CONTINUE;
1091 case LDAP_REQ_EXTENDED:
1092 rc = ldap_chain_op( op, rs, lback->bi_extended, ref, 0 );
1093 /* FIXME: ldap_back_extended() by design
1094 * doesn't send result; frontend is expected
1096 /* FIXME: what about chaining? */
1097 if ( rc != SLAPD_ABANDON ) {
1099 send_ldap_extended( op, rs );
1102 lb.lb_status = LDAP_CH_RES;
1106 rc = SLAP_CB_CONTINUE;
1116 sr_err = rs->sr_err;
1117 /* slapd-ldap sent response */
1118 if ( !op->o_abandon && lb.lb_status != LDAP_CH_RES ) {
1119 /* FIXME: should we send response? */
1120 Debug( LDAP_DEBUG_ANY,
1121 "%s: ldap_chain_response: "
1122 "overlay should have sent result.\n",
1123 op->o_log_prefix, 0, 0 );
1128 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1129 if ( lb.lb_status == LDAP_CH_ERR && rs->sr_err == LDAP_X_CANNOT_CHAIN ) {
1133 switch ( ( get_chainingBehavior( op ) & chain_mask ) >> chain_shift ) {
1134 case LDAP_CHAINING_REQUIRED:
1136 op->o_callback = NULL;
1137 send_ldap_error( op, rs, LDAP_X_CANNOT_CHAIN,
1138 "operation cannot be completed without chaining" );
1142 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1143 if ( LDAP_CHAIN_RETURN_ERR( lc ) ) {
1144 sr_err = rs->sr_err = rc;
1145 rs->sr_type = sr_type;
1148 rc = SLAP_CB_CONTINUE;
1149 rs->sr_err = sr_err;
1150 rs->sr_type = sr_type;
1152 rs->sr_matched = matched;
1155 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1158 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1161 if ( lb.lb_status == LDAP_CH_NONE && rc != SLAPD_ABANDON ) {
1162 /* give the remaining callbacks a chance */
1163 op->o_callback = sc->sc_next;
1164 rc = rs->sr_err = slap_map_api2result( rs );
1165 send_ldap_result( op, rs );
1169 rs->sr_err = sr_err;
1170 rs->sr_type = sr_type;
1172 rs->sr_matched = matched;
1175 op->o_callback = sc;
1181 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1183 ldap_chain_parse_ctrl(
1186 LDAPControl *ctrl );
1189 str2chain( const char *s )
1191 if ( strcasecmp( s, "chainingPreferred" ) == 0 ) {
1192 return LDAP_CHAINING_PREFERRED;
1194 } else if ( strcasecmp( s, "chainingRequired" ) == 0 ) {
1195 return LDAP_CHAINING_REQUIRED;
1197 } else if ( strcasecmp( s, "referralsPreferred" ) == 0 ) {
1198 return LDAP_REFERRALS_PREFERRED;
1200 } else if ( strcasecmp( s, "referralsRequired" ) == 0 ) {
1201 return LDAP_REFERRALS_REQUIRED;
1206 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1221 static ConfigDriver chain_cf_gen;
1222 static ConfigCfAdd chain_cfadd;
1223 static ConfigLDAPadd chain_ldadd;
1224 #ifdef SLAP_CONFIG_DELETE
1225 static ConfigLDAPdel chain_lddel;
1228 static ConfigTable chaincfg[] = {
1229 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1230 { "chain-chaining", "args",
1231 2, 4, 0, ARG_MAGIC|ARG_BERVAL|CH_CHAINING, chain_cf_gen,
1232 "( OLcfgOvAt:3.1 NAME 'olcChainingBehavior' "
1233 "DESC 'Chaining behavior control parameters (draft-sermersheim-ldap-chaining)' "
1234 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
1235 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1236 { "chain-cache-uri", "TRUE/FALSE",
1237 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_CACHE_URI, chain_cf_gen,
1238 "( OLcfgOvAt:3.2 NAME 'olcChainCacheURI' "
1239 "DESC 'Enables caching of URIs not present in configuration' "
1240 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1241 { "chain-max-depth", "args",
1242 2, 2, 0, ARG_MAGIC|ARG_INT|CH_MAX_DEPTH, chain_cf_gen,
1243 "( OLcfgOvAt:3.3 NAME 'olcChainMaxReferralDepth' "
1244 "DESC 'max referral depth' "
1245 "SYNTAX OMsInteger "
1246 "EQUALITY integerMatch "
1247 "SINGLE-VALUE )", NULL, NULL },
1248 { "chain-return-error", "TRUE/FALSE",
1249 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|CH_RETURN_ERR, chain_cf_gen,
1250 "( OLcfgOvAt:3.4 NAME 'olcChainReturnError' "
1251 "DESC 'Errors are returned instead of the original referral' "
1252 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
1253 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1256 static ConfigOCs chainocs[] = {
1257 { "( OLcfgOvOc:3.1 "
1258 "NAME 'olcChainConfig' "
1259 "DESC 'Chain configuration' "
1260 "SUP olcOverlayConfig "
1262 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1263 "olcChainingBehavior $ "
1264 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1265 "olcChainCacheURI $ "
1266 "olcChainMaxReferralDepth $ "
1267 "olcChainReturnError "
1269 Cft_Overlay, chaincfg, NULL, chain_cfadd },
1270 { "( OLcfgOvOc:3.2 "
1271 "NAME 'olcChainDatabase' "
1272 "DESC 'Chain remote server configuration' "
1273 "SUP olcLDAPConfig )",
1274 Cft_Misc, olcDatabaseDummy, chain_ldadd
1275 #ifdef SLAP_CONFIG_DELETE
1283 chain_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
1290 AttributeDescription *ad = NULL;
1296 if ( p->ce_type != Cft_Overlay
1298 || p->ce_bi->bi_cf_ocs != chainocs )
1300 return LDAP_CONSTRAINT_VIOLATION;
1303 on = (slap_overinst *)p->ce_bi;
1304 lc = (ldap_chain_t *)on->on_bi.bi_private;
1306 assert( ca->be == NULL );
1307 ca->be = (BackendDB *)ch_calloc( 1, sizeof( BackendDB ) );
1309 ca->be->bd_info = (BackendInfo *)on;
1311 rc = slap_str2ad( "olcDbURI", &ad, &text );
1312 assert( rc == LDAP_SUCCESS );
1314 at = attr_find( e->e_attrs, ad );
1316 if ( lc->lc_common_li == NULL && at != NULL ) {
1317 /* FIXME: we should generate an empty default entry
1318 * if none is supplied */
1319 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1320 "first underlying database \"%s\" "
1321 "cannot contain attribute \"%s\".\n",
1322 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1323 rc = LDAP_CONSTRAINT_VIOLATION;
1328 if ( lc->lc_common_li != NULL && at == NULL ) {
1329 /* FIXME: we should generate an empty default entry
1330 * if none is supplied */
1331 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1332 "subsequent underlying database \"%s\" "
1333 "must contain attribute \"%s\".\n",
1334 e->e_name.bv_val, ad->ad_cname.bv_val, 0 );
1335 rc = LDAP_CONSTRAINT_VIOLATION;
1339 if ( lc->lc_common_li == NULL ) {
1340 rc = ldap_chain_db_init_common( ca->be );
1343 rc = ldap_chain_db_init_one( ca->be );
1347 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1348 "unable to init %sunderlying database \"%s\".\n",
1349 lc->lc_common_li == NULL ? "common " : "", e->e_name.bv_val, 0 );
1350 return LDAP_CONSTRAINT_VIOLATION;
1353 li = ca->be->be_private;
1355 if ( lc->lc_common_li == NULL ) {
1356 lc->lc_common_li = li;
1359 li->li_uri = ch_strdup( at->a_vals[ 0 ].bv_val );
1360 value_add_one( &li->li_bvuri, &at->a_vals[ 0 ] );
1361 if ( avl_insert( &lc->lc_lai.lai_tree, (caddr_t)li,
1362 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1364 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
1365 "database \"%s\" insert failed.\n",
1366 e->e_name.bv_val, 0, 0 );
1367 rc = LDAP_CONSTRAINT_VIOLATION;
1372 ca->ca_private = on;
1375 if ( rc != LDAP_SUCCESS ) {
1376 (void)ldap_chain_db_destroy_one( ca->be, NULL );
1384 typedef struct ldap_chain_cfadd_apply_t {
1390 } ldap_chain_cfadd_apply_t;
1393 ldap_chain_cfadd_apply( void *datum, void *arg )
1395 ldapinfo_t *li = (ldapinfo_t *)datum;
1396 ldap_chain_cfadd_apply_t *lca = (ldap_chain_cfadd_apply_t *)arg;
1400 /* FIXME: should not hardcode "olcDatabase" here */
1401 bv.bv_len = snprintf( lca->ca->cr_msg, sizeof( lca->ca->cr_msg ),
1402 "olcDatabase={%d}%s", lca->count, lback->bi_type );
1403 bv.bv_val = lca->ca->cr_msg;
1405 lca->ca->be->be_private = (void *)li;
1406 config_build_entry( lca->op, lca->rs, lca->p->e_private, lca->ca,
1407 &bv, lback->bi_cf_ocs, &chainocs[1] );
1415 chain_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca )
1417 CfEntryInfo *pe = p->e_private;
1418 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1419 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1420 void *priv = (void *)ca->be->be_private;
1422 if ( lback->bi_cf_ocs ) {
1423 ldap_chain_cfadd_apply_t lca = { 0 };
1431 (void)ldap_chain_cfadd_apply( (void *)lc->lc_common_li, (void *)&lca );
1433 (void)avl_apply( lc->lc_lai.lai_tree, ldap_chain_cfadd_apply,
1434 &lca, 1, AVL_INORDER );
1436 ca->be->be_private = priv;
1442 #ifdef SLAP_CONFIG_DELETE
1444 chain_lddel( CfEntryInfo *ce, Operation *op )
1446 CfEntryInfo *pe = ce->ce_parent;
1447 slap_overinst *on = (slap_overinst *)pe->ce_bi;
1448 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1449 ldapinfo_t *li = (ldapinfo_t *) ce->ce_be->be_private;
1451 if (! avl_delete( &lc->lc_lai.lai_tree, li, ldap_chain_uri_cmp ) ) {
1452 Debug( LDAP_DEBUG_ANY, "slapd-chain: avl_delete failed. "
1453 "\"%s\" not found.\n", li->li_uri, 0, 0 );
1457 ce->ce_be->bd_info = lback;
1459 if ( ce->ce_be->bd_info->bi_db_close ) {
1460 ce->ce_be->bd_info->bi_db_close( ce->ce_be, NULL );
1462 if ( ce->ce_be->bd_info->bi_db_destroy ) {
1463 ce->ce_be->bd_info->bi_db_destroy( ce->ce_be, NULL );
1469 return LDAP_SUCCESS;
1471 #endif /* SLAP_CONFIG_DELETE */
1473 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1474 static slap_verbmasks chaining_mode[] = {
1475 { BER_BVC("referralsRequired"), LDAP_REFERRALS_REQUIRED },
1476 { BER_BVC("referralsPreferred"), LDAP_REFERRALS_PREFERRED },
1477 { BER_BVC("chainingRequired"), LDAP_CHAINING_REQUIRED },
1478 { BER_BVC("chainingPreferred"), LDAP_CHAINING_PREFERRED },
1481 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1484 chain_cf_gen( ConfigArgs *c )
1486 slap_overinst *on = (slap_overinst *)c->bi;
1487 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1491 if ( c->op == SLAP_CONFIG_EMIT ) {
1493 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1495 struct berval resolve = BER_BVNULL,
1496 continuation = BER_BVNULL;
1498 if ( !LDAP_CHAIN_CHAINING( lc ) ) {
1502 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_RESOLVE_MASK ) >> SLAP_CH_RESOLVE_SHIFT ), &resolve );
1503 enum_to_verb( chaining_mode, ( ( lc->lc_chaining_ctrlflag & SLAP_CH_CONTINUATION_MASK ) >> SLAP_CH_CONTINUATION_SHIFT ), &continuation );
1505 c->value_bv.bv_len = STRLENOF( "resolve=" ) + resolve.bv_len
1507 + STRLENOF( "continuation=" ) + continuation.bv_len;
1508 c->value_bv.bv_val = ch_malloc( c->value_bv.bv_len + 1 );
1509 snprintf( c->value_bv.bv_val, c->value_bv.bv_len + 1,
1510 "resolve=%s continuation=%s",
1511 resolve.bv_val, continuation.bv_val );
1513 if ( lc->lc_chaining_ctrl.ldctl_iscritical ) {
1514 c->value_bv.bv_val = ch_realloc( c->value_bv.bv_val,
1515 c->value_bv.bv_len + STRLENOF( " critical" ) + 1 );
1516 AC_MEMCPY( &c->value_bv.bv_val[ c->value_bv.bv_len ],
1517 " critical", STRLENOF( " critical" ) + 1 );
1518 c->value_bv.bv_len += STRLENOF( " critical" );
1523 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1526 c->value_int = LDAP_CHAIN_CACHE_URI( lc );
1530 c->value_int = lc->lc_max_depth;
1534 c->value_int = LDAP_CHAIN_RETURN_ERR( lc );
1543 } else if ( c->op == LDAP_MOD_DELETE ) {
1549 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1557 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1568 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1569 char **argv = c->argv;
1571 BerElementBuffer berbuf;
1572 BerElement *ber = (BerElement *)&berbuf;
1576 Operation op = { 0 };
1577 SlapReply rs = { 0 };
1579 lc->lc_chaining_ctrlflag = 0;
1581 for ( argc--, argv++; argc > 0; argc--, argv++ ) {
1582 if ( strncasecmp( argv[ 0 ], "resolve=", STRLENOF( "resolve=" ) ) == 0 ) {
1583 resolve = str2chain( argv[ 0 ] + STRLENOF( "resolve=" ) );
1584 if ( resolve == -1 ) {
1585 Debug( LDAP_DEBUG_ANY, "%s: "
1586 "illegal <resolve> value %s "
1587 "in \"chain-chaining>\".\n",
1588 c->log, argv[ 0 ], 0 );
1592 } else if ( strncasecmp( argv[ 0 ], "continuation=", STRLENOF( "continuation=" ) ) == 0 ) {
1593 continuation = str2chain( argv[ 0 ] + STRLENOF( "continuation=" ) );
1594 if ( continuation == -1 ) {
1595 Debug( LDAP_DEBUG_ANY, "%s: "
1596 "illegal <continuation> value %s "
1597 "in \"chain-chaining\".\n",
1598 c->log, argv[ 0 ], 0 );
1602 } else if ( strcasecmp( argv[ 0 ], "critical" ) == 0 ) {
1606 Debug( LDAP_DEBUG_ANY, "%s: "
1607 "unknown option in \"chain-chaining\".\n",
1613 if ( resolve != -1 || continuation != -1 ) {
1616 if ( resolve == -1 ) {
1618 resolve = SLAP_CHAINING_DEFAULT;
1621 ber_init2( ber, NULL, LBER_USE_DER );
1623 err = ber_printf( ber, "{e" /* } */, resolve );
1626 Debug( LDAP_DEBUG_ANY, "%s: "
1627 "chaining behavior control encoding error!\n",
1632 if ( continuation > -1 ) {
1633 err = ber_printf( ber, "e", continuation );
1636 Debug( LDAP_DEBUG_ANY, "%s: "
1637 "chaining behavior control encoding error!\n",
1643 err = ber_printf( ber, /* { */ "N}" );
1646 Debug( LDAP_DEBUG_ANY, "%s: "
1647 "chaining behavior control encoding error!\n",
1652 if ( ber_flatten2( ber, &lc->lc_chaining_ctrl.ldctl_value, 0 ) == -1 ) {
1653 exit( EXIT_FAILURE );
1657 BER_BVZERO( &lc->lc_chaining_ctrl.ldctl_value );
1660 lc->lc_chaining_ctrl.ldctl_oid = LDAP_CONTROL_X_CHAINING_BEHAVIOR;
1661 lc->lc_chaining_ctrl.ldctl_iscritical = iscritical;
1663 if ( ldap_chain_parse_ctrl( &op, &rs, &lc->lc_chaining_ctrl ) != LDAP_SUCCESS )
1665 Debug( LDAP_DEBUG_ANY, "%s: "
1666 "unable to parse chaining control%s%s.\n",
1667 c->log, rs.sr_text ? ": " : "",
1668 rs.sr_text ? rs.sr_text : "" );
1672 lc->lc_chaining_ctrlflag = op.o_chaining;
1674 lc->lc_flags |= LDAP_CHAIN_F_CHAINING;
1677 #else /* ! LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1678 Debug( LDAP_DEBUG_ANY, "%s: "
1679 "\"chaining\" control unsupported (ignored).\n",
1681 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1685 if ( c->value_int ) {
1686 lc->lc_flags |= LDAP_CHAIN_F_CACHE_URI;
1688 lc->lc_flags &= ~LDAP_CHAIN_F_CACHE_URI;
1693 if ( c->value_int < 0 ) {
1694 snprintf( c->cr_msg, sizeof( c->cr_msg ),
1695 "<%s> invalid max referral depth %d",
1696 c->argv[0], c->value_int );
1697 Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
1698 c->log, c->cr_msg, 0 );
1702 lc->lc_max_depth = c->value_int;
1705 if ( c->value_int ) {
1706 lc->lc_flags |= LDAP_CHAIN_F_RETURN_ERR;
1708 lc->lc_flags &= ~LDAP_CHAIN_F_RETURN_ERR;
1724 slap_overinst *on = (slap_overinst *)be->bd_info;
1725 ldap_chain_t *lc = NULL;
1727 if ( lback == NULL ) {
1728 lback = backend_info( "ldap" );
1730 if ( lback == NULL ) {
1735 lc = ch_malloc( sizeof( ldap_chain_t ) );
1739 memset( lc, 0, sizeof( ldap_chain_t ) );
1740 lc->lc_max_depth = 1;
1741 ldap_pvt_thread_mutex_init( &lc->lc_lai.lai_mutex );
1743 on->on_bi.bi_private = (void *)lc;
1749 ldap_chain_db_config(
1756 slap_overinst *on = (slap_overinst *)be->bd_info;
1757 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1759 int rc = SLAP_CONF_UNKNOWN;
1761 if ( lc->lc_common_li == NULL ) {
1763 ldap_chain_db_init_common( &db );
1764 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)db.be_private;
1767 /* Something for the chain database? */
1768 if ( strncasecmp( argv[ 0 ], "chain-", STRLENOF( "chain-" ) ) == 0 ) {
1769 char *save_argv0 = argv[ 0 ];
1771 static char *allowed_argv[] = {
1772 /* special: put URI here, so in the meanwhile
1773 * it detects whether a new URI is being provided */
1779 /* FIXME: maybe rebind-as-user should be allowed
1780 * only within known URIs... */
1787 int which_argv = -1;
1789 argv[ 0 ] += STRLENOF( "chain-" );
1791 for ( which_argv = 0; allowed_argv[ which_argv ]; which_argv++ ) {
1792 if ( strcasecmp( argv[ 0 ], allowed_argv[ which_argv ] ) == 0 ) {
1797 if ( allowed_argv[ which_argv ] == NULL ) {
1800 if ( lc->lc_cfg_li == lc->lc_common_li ) {
1801 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1802 "\"%s\" only allowed within a URI directive.\n.",
1803 fname, lineno, argv[ 0 ] );
1808 if ( which_argv == 0 ) {
1809 rc = ldap_chain_db_init_one( &db );
1811 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1812 "underlying slapd-ldap initialization failed.\n.",
1816 lc->lc_cfg_li = db.be_private;
1819 /* TODO: add checks on what other slapd-ldap(5) args
1820 * should be put in the template; this is not quite
1821 * harmful, because attributes that shouldn't don't
1822 * get actually used, but the user should at least
1827 db.be_private = (void *)lc->lc_cfg_li;
1828 db.be_cf_ocs = lback->bi_cf_ocs;
1830 rc = config_generic_wrapper( &db, fname, lineno, argc, argv );
1832 argv[ 0 ] = save_argv0;
1834 if ( which_argv == 0 ) {
1838 db.be_private = (void *)lc->lc_cfg_li;
1839 ldap_chain_db_destroy_one( &db, NULL );
1840 lc->lc_cfg_li = NULL;
1842 if ( lc->lc_cfg_li->li_bvuri == NULL
1843 || BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 0 ] )
1844 || !BER_BVISNULL( &lc->lc_cfg_li->li_bvuri[ 1 ] ) )
1846 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1847 "no URI list allowed in slapo-chain.\n",
1850 goto private_destroy;
1853 if ( avl_insert( &lc->lc_lai.lai_tree,
1854 (caddr_t)lc->lc_cfg_li,
1855 ldap_chain_uri_cmp, ldap_chain_uri_dup ) )
1857 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1858 "duplicate URI in slapo-chain.\n",
1861 goto private_destroy;
1878 typedef struct ldap_chain_db_apply_t {
1881 } ldap_chain_db_apply_t;
1884 ldap_chain_db_apply( void *datum, void *arg )
1886 ldapinfo_t *li = (ldapinfo_t *)datum;
1887 ldap_chain_db_apply_t *lca = (ldap_chain_db_apply_t *)arg;
1889 lca->be->be_private = (void *)li;
1891 return lca->func( lca->be, NULL );
1900 slap_overinst *on = (slap_overinst *)be->bd_info;
1901 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1906 BI_db_func *func = (&lback->bi_db_open)[ which ];
1908 if ( func != NULL && lc->lc_common_li != NULL ) {
1912 db.be_private = lc->lc_common_li;
1914 rc = func( &db, NULL );
1920 if ( lc->lc_lai.lai_tree != NULL ) {
1921 ldap_chain_db_apply_t lca;
1926 rc = avl_apply( lc->lc_lai.lai_tree,
1927 ldap_chain_db_apply, (void *)&lca,
1928 1, AVL_INORDER ) != AVL_NOMORE;
1941 slap_overinst *on = (slap_overinst *) be->bd_info;
1942 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1943 slap_mask_t monitoring;
1946 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
1947 rc = overlay_register_control( be, LDAP_CONTROL_X_CHAINING_BEHAVIOR );
1951 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
1953 if ( lc->lc_common_li == NULL ) {
1954 void *be_private = be->be_private;
1955 ldap_chain_db_init_common( be );
1956 lc->lc_common_li = lc->lc_cfg_li = (ldapinfo_t *)be->be_private;
1957 be->be_private = be_private;
1960 /* filter out and restore monitoring */
1961 monitoring = ( SLAP_DBFLAGS( be ) & SLAP_DBFLAG_MONITORING );
1962 SLAP_DBFLAGS( be ) &= ~SLAP_DBFLAG_MONITORING;
1963 rc = ldap_chain_db_func( be, db_open );
1964 SLAP_DBFLAGS( be ) |= monitoring;
1970 ldap_chain_db_close(
1974 return ldap_chain_db_func( be, db_close );
1978 ldap_chain_db_destroy(
1982 slap_overinst *on = (slap_overinst *) be->bd_info;
1983 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
1987 rc = ldap_chain_db_func( be, db_destroy );
1990 avl_free( lc->lc_lai.lai_tree, NULL );
1991 ldap_pvt_thread_mutex_destroy( &lc->lc_lai.lai_mutex );
1999 * inits one instance of the slapd-ldap backend, and stores
2000 * the private info in be_private of the arg
2003 ldap_chain_db_init_common(
2006 BackendInfo *bi = be->bd_info;
2010 be->bd_info = lback;
2011 be->be_private = NULL;
2012 rc = lback->bi_db_init( be, NULL );
2016 li = (ldapinfo_t *)be->be_private;
2017 li->li_urllist_f = NULL;
2018 li->li_urllist_p = NULL;
2026 * inits one instance of the slapd-ldap backend, stores
2027 * the private info in be_private of the arg and fills
2028 * selected fields with data from the template.
2030 * NOTE: add checks about the other fields of the template,
2031 * which are ignored and SHOULD NOT be configured by the user.
2034 ldap_chain_db_init_one(
2037 slap_overinst *on = (slap_overinst *)be->bd_info;
2038 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
2040 BackendInfo *bi = be->bd_info;
2045 be->bd_info = lback;
2046 be->be_private = NULL;
2047 t = lback->bi_db_init( be, NULL );
2051 li = (ldapinfo_t *)be->be_private;
2052 li->li_urllist_f = NULL;
2053 li->li_urllist_p = NULL;
2055 /* copy common data */
2056 li->li_nretries = lc->lc_common_li->li_nretries;
2057 li->li_flags = lc->lc_common_li->li_flags;
2058 li->li_version = lc->lc_common_li->li_version;
2059 for ( t = 0; t < SLAP_OP_LAST; t++ ) {
2060 li->li_timeout[ t ] = lc->lc_common_li->li_timeout[ t ];
2068 ldap_chain_db_open_one(
2071 if ( SLAP_DBMONITORING( be ) ) {
2072 ldapinfo_t *li = (ldapinfo_t *)be->be_private;
2074 if ( li->li_uri == NULL ) {
2075 ber_str2bv( "cn=Common Connections", 0, 1,
2076 &li->li_monitor_info.lmi_rdn );
2081 li->li_monitor_info.lmi_rdn.bv_len
2082 = STRLENOF( "cn=" ) + strlen( li->li_uri );
2083 ptr = li->li_monitor_info.lmi_rdn.bv_val
2084 = ch_malloc( li->li_monitor_info.lmi_rdn.bv_len + 1 );
2085 ptr = lutil_strcopy( ptr, "cn=" );
2086 ptr = lutil_strcopy( ptr, li->li_uri );
2091 return lback->bi_db_open( be, NULL );
2094 typedef struct ldap_chain_conn_apply_t {
2097 } ldap_chain_conn_apply_t;
2100 ldap_chain_conn_apply( void *datum, void *arg )
2102 ldapinfo_t *li = (ldapinfo_t *)datum;
2103 ldap_chain_conn_apply_t *lca = (ldap_chain_conn_apply_t *)arg;
2105 lca->be->be_private = (void *)li;
2107 return lback->bi_connection_destroy( lca->be, lca->conn );
2111 ldap_chain_connection_destroy(
2116 slap_overinst *on = (slap_overinst *) be->bd_info;
2117 ldap_chain_t *lc = (ldap_chain_t *)on->on_bi.bi_private;
2118 void *private = be->be_private;
2119 ldap_chain_conn_apply_t lca;
2122 be->be_private = NULL;
2125 ldap_pvt_thread_mutex_lock( &lc->lc_lai.lai_mutex );
2126 rc = avl_apply( lc->lc_lai.lai_tree, ldap_chain_conn_apply,
2127 (void *)&lca, 1, AVL_INORDER ) != AVL_NOMORE;
2128 ldap_pvt_thread_mutex_unlock( &lc->lc_lai.lai_mutex );
2129 be->be_private = private;
2134 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2136 ldap_chain_parse_ctrl(
2146 if ( get_chaining( op ) != SLAP_CONTROL_NONE ) {
2147 rs->sr_text = "Chaining behavior control specified multiple times";
2148 return LDAP_PROTOCOL_ERROR;
2151 if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
2152 rs->sr_text = "Chaining behavior control specified with pagedResults control";
2153 return LDAP_PROTOCOL_ERROR;
2156 if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
2157 mode = (SLAP_CH_RESOLVE_DEFAULT|SLAP_CH_CONTINUATION_DEFAULT);
2162 /* Parse the control value
2163 * ChainingBehavior ::= SEQUENCE {
2164 * resolveBehavior Behavior OPTIONAL,
2165 * continuationBehavior Behavior OPTIONAL }
2167 * Behavior :: = ENUMERATED {
2168 * chainingPreferred (0),
2169 * chainingRequired (1),
2170 * referralsPreferred (2),
2171 * referralsRequired (3) }
2174 ber = ber_init( &ctrl->ldctl_value );
2176 rs->sr_text = "internal error";
2180 tag = ber_scanf( ber, "{e" /* } */, &behavior );
2181 /* FIXME: since the whole SEQUENCE is optional,
2182 * should we accept no enumerations at all? */
2183 if ( tag != LBER_ENUMERATED ) {
2184 rs->sr_text = "Chaining behavior control: resolveBehavior decoding error";
2185 return LDAP_PROTOCOL_ERROR;
2188 switch ( behavior ) {
2189 case LDAP_CHAINING_PREFERRED:
2190 mode = SLAP_CH_RESOLVE_CHAINING_PREFERRED;
2193 case LDAP_CHAINING_REQUIRED:
2194 mode = SLAP_CH_RESOLVE_CHAINING_REQUIRED;
2197 case LDAP_REFERRALS_PREFERRED:
2198 mode = SLAP_CH_RESOLVE_REFERRALS_PREFERRED;
2201 case LDAP_REFERRALS_REQUIRED:
2202 mode = SLAP_CH_RESOLVE_REFERRALS_REQUIRED;
2206 rs->sr_text = "Chaining behavior control: unknown resolveBehavior";
2207 return LDAP_PROTOCOL_ERROR;
2210 tag = ber_peek_tag( ber, &len );
2211 if ( tag == LBER_ENUMERATED ) {
2212 tag = ber_scanf( ber, "e", &behavior );
2213 if ( tag == LBER_ERROR ) {
2214 rs->sr_text = "Chaining behavior control: continuationBehavior decoding error";
2215 return LDAP_PROTOCOL_ERROR;
2219 if ( tag == LBER_DEFAULT ) {
2220 mode |= SLAP_CH_CONTINUATION_DEFAULT;
2223 switch ( behavior ) {
2224 case LDAP_CHAINING_PREFERRED:
2225 mode |= SLAP_CH_CONTINUATION_CHAINING_PREFERRED;
2228 case LDAP_CHAINING_REQUIRED:
2229 mode |= SLAP_CH_CONTINUATION_CHAINING_REQUIRED;
2232 case LDAP_REFERRALS_PREFERRED:
2233 mode |= SLAP_CH_CONTINUATION_REFERRALS_PREFERRED;
2236 case LDAP_REFERRALS_REQUIRED:
2237 mode |= SLAP_CH_CONTINUATION_REFERRALS_REQUIRED;
2241 rs->sr_text = "Chaining behavior control: unknown continuationBehavior";
2242 return LDAP_PROTOCOL_ERROR;
2246 if ( ( ber_scanf( ber, /* { */ "}") ) == LBER_ERROR ) {
2247 rs->sr_text = "Chaining behavior control: decoding error";
2248 return LDAP_PROTOCOL_ERROR;
2251 (void) ber_free( ber, 1 );
2254 op->o_chaining = mode | ( ctrl->ldctl_iscritical
2255 ? SLAP_CONTROL_CRITICAL
2256 : SLAP_CONTROL_NONCRITICAL );
2258 return LDAP_SUCCESS;
2260 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2263 chain_initialize( void )
2267 /* Make sure we don't exceed the bits reserved for userland */
2268 config_check_userland( CH_LAST );
2270 #ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
2271 rc = register_supported_control( LDAP_CONTROL_X_CHAINING_BEHAVIOR,
2272 /* SLAP_CTRL_GLOBAL| */ SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE, NULL,
2273 ldap_chain_parse_ctrl, &sc_chainingBehavior );
2274 if ( rc != LDAP_SUCCESS ) {
2275 Debug( LDAP_DEBUG_ANY, "slapd-chain: "
2276 "unable to register chaining behavior control: %d.\n",
2280 #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
2282 ldapchain.on_bi.bi_type = "chain";
2283 ldapchain.on_bi.bi_db_init = ldap_chain_db_init;
2284 ldapchain.on_bi.bi_db_config = ldap_chain_db_config;
2285 ldapchain.on_bi.bi_db_open = ldap_chain_db_open;
2286 ldapchain.on_bi.bi_db_close = ldap_chain_db_close;
2287 ldapchain.on_bi.bi_db_destroy = ldap_chain_db_destroy;
2289 ldapchain.on_bi.bi_connection_destroy = ldap_chain_connection_destroy;
2291 ldapchain.on_response = ldap_chain_response;
2293 ldapchain.on_bi.bi_cf_ocs = chainocs;
2295 rc = config_register_schema( chaincfg, chainocs );
2300 return overlay_register( &ldapchain );