1 /* bind.c - bind request handler functions for binding
2 * to remote targets for back-asyncmeta */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 * Copyright 2016 The OpenLDAP Foundation.
7 * Portions Copyright 2016 Symas Corporation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
20 * This work was developed by Symas Corporation
21 * based on back-meta module for inclusion in OpenLDAP Software.
22 * This work was sponsored by Ericsson. */
29 #include <ac/socket.h>
30 #include <ac/string.h>
35 #include "../back-ldap/back-ldap.h"
36 #include "back-asyncmeta.h"
38 #include "lutil_ldap.h"
41 asyncmeta_proxy_authz_bind(
46 ldap_back_send_t sendok,
50 asyncmeta_single_bind(
57 asyncmeta_back_bind( Operation *op, SlapReply *rs )
59 a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
60 a_metaconn_t *mc = NULL;
67 SlapReply *candidates;
69 candidates = op->o_tmpcalloc(mi->mi_ntargets, sizeof(SlapReply),op->o_tmpmemctx);
70 rs->sr_err = LDAP_SUCCESS;
72 Debug( LDAP_DEBUG_ARGS, "%s asyncmeta_back_bind: dn=\"%s\".\n",
73 op->o_log_prefix, op->o_req_dn.bv_val, 0 );
75 /* the test on the bind method should be superfluous */
76 switch ( be_rootdn_bind( op, rs ) ) {
78 if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
79 /* frontend will return success */
86 case SLAP_CB_CONTINUE:
90 /* be_rootdn_bind() sent result */
94 /* we need asyncmeta_getconn() not send result even on error,
95 * because we want to intercept the error and make it
96 * invalidCredentials */
97 mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_BIND_DONTSEND, 1 );
99 if ( LogTest( LDAP_DEBUG_ANY ) ) {
100 char buf[ SLAP_TEXT_BUFLEN ];
102 snprintf( buf, sizeof( buf ),
103 "asyncmeta_back_bind: no target "
104 "for dn \"%s\" (%d%s%s).",
105 op->o_req_dn.bv_val, rs->sr_err,
106 rs->sr_text ? ". " : "",
107 rs->sr_text ? rs->sr_text : "" );
108 Debug( LDAP_DEBUG_ANY,
110 op->o_log_prefix, buf, 0 );
113 /* FIXME: there might be cases where we don't want
114 * to map the error onto invalidCredentials */
115 switch ( rs->sr_err ) {
116 case LDAP_NO_SUCH_OBJECT:
117 case LDAP_UNWILLING_TO_PERFORM:
118 rs->sr_err = LDAP_INVALID_CREDENTIALS;
122 send_ldap_result( op, rs );
127 * Each target is scanned ...
129 mc->mc_authz_target = META_BOUND_NONE;
130 for ( i = 0; i < mi->mi_ntargets; i++ ) {
131 a_metatarget_t *mt = mi->mi_targets[ i ];
135 * Skip non-candidates
137 if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
142 /* set rc to LDAP_SUCCESS only if at least
143 * one candidate has been tried */
147 } else if ( !isroot ) {
149 * A bind operation is expected to have
150 * ONE CANDIDATE ONLY!
152 Debug( LDAP_DEBUG_ANY,
153 "### %s asyncmeta_back_bind: more than one"
154 " candidate selected...\n",
155 op->o_log_prefix, 0, 0 );
159 if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
160 || BER_BVISNULL( &mt->mt_idassert_authcDN ) )
162 a_metasingleconn_t *msc = &mc->mc_conns[ i ];
164 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
165 ch_free( msc->msc_bound_ndn.bv_val );
166 BER_BVZERO( &msc->msc_bound_ndn );
169 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
170 /* destroy sensitive data */
171 memset( msc->msc_cred.bv_val, 0,
172 msc->msc_cred.bv_len );
173 ch_free( msc->msc_cred.bv_val );
174 BER_BVZERO( &msc->msc_cred );
181 (void)asyncmeta_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 );
185 lerr = asyncmeta_single_bind( op, rs, mc, i );
188 if ( lerr != LDAP_SUCCESS ) {
189 rc = rs->sr_err = lerr;
191 /* FIXME: in some cases (e.g. unavailable)
192 * do not assume it's not candidate; rather
193 * mark this as an error to be eventually
194 * reported to client */
195 META_CANDIDATE_CLEAR( &candidates[ i ] );
201 for ( i = 0; i < mi->mi_ntargets; i++ ) {
202 a_metasingleconn_t *msc = &mc->mc_conns[ i ];
203 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
204 ch_free( msc->msc_bound_ndn.bv_val );
207 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
208 /* destroy sensitive data */
209 memset( msc->msc_cred.bv_val, 0,
210 msc->msc_cred.bv_len );
211 ch_free( msc->msc_cred.bv_val );
214 asyncmeta_back_conn_free( mc );
218 * rc is LDAP_SUCCESS if at least one bind succeeded,
219 * err is the last error that occurred during a bind;
220 * if at least (and at most?) one bind succeeds, fine.
222 if ( rc != LDAP_SUCCESS ) {
225 * deal with bind failure ...
229 * no target was found within the naming context,
230 * so bind must fail with invalid credentials
232 if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
233 rs->sr_err = LDAP_INVALID_CREDENTIALS;
235 rs->sr_err = slap_map_api2result( rs );
237 send_ldap_result( op, rs );
245 asyncmeta_bind_op_result(
251 ldap_back_send_t sendok,
254 a_metainfo_t *mi = mc->mc_info;
255 a_metatarget_t *mt = mi->mi_targets[ candidate ];
256 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
260 int nretries = mt->mt_nretries;
261 char buf[ SLAP_TEXT_BUFLEN ];
263 Debug( LDAP_DEBUG_TRACE,
264 ">>> %s asyncmeta_bind_op_result[%d]\n",
265 op->o_log_prefix, candidate, 0 );
267 /* make sure this is clean */
268 assert( rs->sr_ctrls == NULL );
270 if ( rs->sr_err == LDAP_SUCCESS ) {
271 time_t stoptime = (time_t)(-1),
273 int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
274 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
275 const char *timeout_text = "Operation timed out";
276 slap_op_t opidx = slap_req2op( op->o_tag );
278 /* since timeout is not specified, compute and use
279 * the one specific to the ongoing operation */
280 if ( opidx == LDAP_REQ_SEARCH ) {
281 if ( op->ors_tlimit <= 0 ) {
285 timeout = op->ors_tlimit;
286 timeout_err = LDAP_TIMELIMIT_EXCEEDED;
291 timeout = mt->mt_timeout[ opidx ];
294 /* better than nothing :) */
295 if ( timeout == 0 ) {
296 if ( mi->mi_idle_timeout ) {
297 timeout = mi->mi_idle_timeout;
303 stoptime = op->o_time + timeout;
306 LDAP_BACK_TV_SET( &tv );
312 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
315 if ( nretries != META_RETRY_NEVER
316 || ( timeout && slap_get_time() <= stoptime ) )
318 ldap_pvt_thread_yield();
319 if ( nretries > 0 ) {
322 tv = mt->mt_bind_timeout;
326 /* don't let anyone else use this handler,
327 * because there's a pending bind that will not
329 assert( LDAP_BACK_CONN_BINDING( msc ) );
332 Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
333 op->o_log_prefix, candidate, (void *)msc->msc_ld );
334 #endif /* DEBUG_205 */
336 rs->sr_err = timeout_err;
337 rs->sr_text = timeout_text;
341 ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
344 snprintf( buf, sizeof( buf ),
345 "err=%d (%s) nretries=%d",
346 rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
347 Debug( LDAP_DEBUG_ANY,
348 "### %s asyncmeta_bind_op_result[%d]: %s.\n",
349 op->o_log_prefix, candidate, buf );
353 /* only touch when activity actually took place... */
354 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
355 msc->msc_time = op->o_time;
358 /* FIXME: matched? referrals? response controls? */
359 rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
360 NULL, NULL, NULL, NULL, 1 );
361 if ( rc != LDAP_SUCCESS ) {
364 rs->sr_err = slap_map_api2result( rs );
369 rs->sr_err = slap_map_api2result( rs );
370 Debug( LDAP_DEBUG_TRACE,
371 "<<< %s asyncmeta_bind_op_result[%d] err=%d\n",
372 op->o_log_prefix, candidate, rs->sr_err );
378 * asyncmeta_single_bind
380 * attempts to perform a bind with creds
383 asyncmeta_single_bind(
389 a_metainfo_t *mi = mc->mc_info;
390 a_metatarget_t *mt = mi->mi_targets[ candidate ];
391 struct berval mdn = BER_BVNULL;
392 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
395 struct berval save_o_dn;
396 int save_o_do_not_cache;
397 LDAPControl **ctrls = NULL;
399 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
400 ch_free( msc->msc_bound_ndn.bv_val );
401 BER_BVZERO( &msc->msc_bound_ndn );
404 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
405 /* destroy sensitive data */
406 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
407 ch_free( msc->msc_cred.bv_val );
408 BER_BVZERO( &msc->msc_cred );
412 * Rewrite the bind dn if needed
415 dc.conn = op->o_conn;
419 if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
420 rs->sr_text = "DN rewrite error";
421 rs->sr_err = LDAP_OTHER;
425 /* don't add proxyAuthz; set the bindDN */
426 save_o_dn = op->o_dn;
427 save_o_do_not_cache = op->o_do_not_cache;
428 op->o_do_not_cache = 1;
429 op->o_dn = op->o_req_dn;
432 rs->sr_err = asyncmeta_controls_add( op, rs, mc, candidate, &ctrls );
433 op->o_dn = save_o_dn;
434 op->o_do_not_cache = save_o_do_not_cache;
435 if ( rs->sr_err != LDAP_SUCCESS ) {
439 /* FIXME: this fixes the bind problem right now; we need
440 * to use the asynchronous version to get the "matched"
441 * and more in case of failure ... */
442 /* FIXME: should we check if at least some of the op->o_ctrls
443 * can/should be passed? */
445 rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
446 LDAP_SASL_SIMPLE, &op->orb_cred,
447 ctrls, NULL, &msgid );
448 if ( rs->sr_err != LDAP_X_CONNECTING ) {
451 ldap_pvt_thread_yield();
454 mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
456 asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 );
457 if ( rs->sr_err != LDAP_SUCCESS ) {
461 /* If defined, proxyAuthz will be used also when
462 * back-ldap is the authorizing backend; for this
463 * purpose, a successful bind is followed by a
464 * bind with the configured identity assertion */
465 /* NOTE: use with care */
466 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
467 asyncmeta_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 );
468 if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
474 ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
475 LDAP_BACK_CONN_ISBOUND_SET( msc );
476 mc->mc_authz_target = candidate;
478 if ( META_BACK_TGT_SAVECRED( mt ) ) {
479 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
480 memset( msc->msc_cred.bv_val, 0,
481 msc->msc_cred.bv_len );
483 ber_bvreplace( &msc->msc_cred, &op->orb_cred );
484 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
488 if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
489 && !BER_BVISEMPTY( &op->o_req_ndn ) )
491 ( void )asyncmeta_dncache_update_entry( &mi->mi_cache,
492 &op->o_req_ndn, candidate );
496 if ( mdn.bv_val != op->o_req_dn.bv_val ) {
500 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
501 asyncmeta_quarantine( op, mi, rs, candidate );
503 ldap_unbind_ext( msc->msc_ld, NULL, NULL );
505 ldap_ld_free( msc->msc_ldr, 0, NULL, NULL );
511 * asyncmeta_back_single_dobind
514 asyncmeta_back_single_dobind(
519 ldap_back_send_t sendok,
523 a_metaconn_t *mc = *mcp;
524 a_metainfo_t *mi = mc->mc_info;
525 a_metatarget_t *mt = mi->mi_targets[ candidate ];
526 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
529 assert( !LDAP_BACK_CONN_ISBOUND( msc ) );
531 if ( op->o_conn != NULL &&
532 !op->o_do_not_cache &&
533 ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
534 BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
535 ( LDAP_BACK_CONN_ISPRIV( mc ) && dn_match( &msc->msc_bound_ndn, &mt->mt_idassert_authcDN ) ) ||
536 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
538 (void)asyncmeta_proxy_authz_bind( mc, candidate, op, rs, sendok, dolock );
542 struct berval cred = BER_BVC( "" );
544 /* use credentials if available */
545 if ( !BER_BVISNULL( &msc->msc_bound_ndn )
546 && !BER_BVISNULL( &msc->msc_cred ) )
548 binddn = msc->msc_bound_ndn.bv_val;
549 cred = msc->msc_cred;
553 rs->sr_err = ldap_sasl_bind( msc->msc_ld,
554 binddn, LDAP_SASL_SIMPLE, &cred,
555 NULL, NULL, &msgid );
556 if ( rs->sr_err != LDAP_X_CONNECTING ) {
559 ldap_pvt_thread_yield();
562 rs->sr_err = asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
564 /* if bind succeeded, but anonymous, clear msc_bound_ndn */
565 if ( rs->sr_err != LDAP_SUCCESS || binddn[0] == '\0' ) {
566 if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
567 ber_memfree( msc->msc_bound_ndn.bv_val );
568 BER_BVZERO( &msc->msc_bound_ndn );
571 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
572 memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
573 ber_memfree( msc->msc_cred.bv_val );
574 BER_BVZERO( &msc->msc_cred );
579 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
580 asyncmeta_quarantine( op, mi, rs, candidate );
587 * asyncmeta_back_default_rebind
589 * This is a callback used for chasing referrals using the same
590 * credentials as the original user on this session.
593 asyncmeta_back_default_rebind(
595 LDAP_CONST char *url,
600 a_metasingleconn_t *msc = ( a_metasingleconn_t * )params;
602 return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
603 LDAP_SASL_SIMPLE, &msc->msc_cred,
608 * meta_back_default_urllist
610 * This is a callback used for mucking with the urllist
613 asyncmeta_back_default_urllist(
615 LDAPURLDesc **urllist,
619 a_metatarget_t *mt = (a_metatarget_t *)params;
620 LDAPURLDesc **urltail;
622 if ( urllist == url ) {
626 for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
633 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
635 ch_free( mt->mt_uri );
638 ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
639 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
645 asyncmeta_back_cancel(
652 a_metainfo_t *mi = mc->mc_info;
653 a_metatarget_t *mt = mi->mi_targets[ candidate ];
654 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
658 Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n",
659 op->o_log_prefix, candidate, msgid );
661 if (msc->msc_ld == NULL) {
662 Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n already reset",
663 op->o_log_prefix, candidate, msgid );
667 /* default behavior */
668 if ( META_BACK_TGT_ABANDON( mt ) ) {
669 rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
671 } else if ( META_BACK_TGT_IGNORE( mt ) ) {
672 rc = ldap_pvt_discard( msc->msc_ld, msgid );
674 } else if ( META_BACK_TGT_CANCEL( mt ) ) {
675 rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
681 Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_cancel[%d] err=%d\n",
682 op->o_log_prefix, candidate, rc );
689 asyncmeta_back_abandon_candidate(
696 a_metainfo_t *mi = mc->mc_info;
697 a_metatarget_t *mt = mi->mi_targets[ candidate ];
698 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
702 Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_abandon[%d] msgid=%d\n",
703 op->o_log_prefix, candidate, msgid );
705 rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
707 Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_abandon[%d] err=%d\n",
708 op->o_log_prefix, candidate, rc );
714 asyncmeta_back_cancel_msc(
718 a_metasingleconn_t *msc,
720 ldap_back_send_t sendok )
722 a_metainfo_t *mi = (a_metainfo_t *)op->o_bd->be_private;
724 a_metatarget_t *mt = mi->mi_targets[ candidate ];
728 Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel_msc[%d] msgid=%d\n",
729 op->o_log_prefix, candidate, msgid );
731 /* default behavior */
732 if ( META_BACK_TGT_ABANDON( mt ) ) {
733 rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
735 } else if ( META_BACK_TGT_IGNORE( mt ) ) {
736 rc = ldap_pvt_discard( msc->msc_ld, msgid );
738 } else if ( META_BACK_TGT_CANCEL( mt ) ) {
739 rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
745 Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_cancel_msc[%d] err=%d\n",
746 op->o_log_prefix, candidate, rc );
752 * FIXME: error return must be handled in a cleaner way ...
755 asyncmeta_back_op_result(
762 ldap_back_send_t sendok )
764 a_metainfo_t *mi = mc->mc_info;
766 const char *save_text = rs->sr_text,
767 *save_matched = rs->sr_matched;
768 BerVarray save_ref = rs->sr_ref;
769 LDAPControl **save_ctrls = rs->sr_ctrls;
770 void *matched_ctx = NULL;
772 char *matched = NULL;
775 LDAPControl **ctrls = NULL;
777 assert( mc != NULL );
780 rs->sr_matched = NULL;
784 if ( candidate != META_TARGET_NONE ) {
785 a_metatarget_t *mt = mi->mi_targets[ candidate ];
786 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
788 if ( LDAP_ERR_OK( rs->sr_err ) ) {
791 LDAPMessage *res = NULL;
792 time_t stoptime = (time_t)(-1);
793 int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
794 LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
795 const char *timeout_text = "Operation timed out";
797 /* if timeout is not specified, compute and use
798 * the one specific to the ongoing operation */
799 if ( timeout == (time_t)(-1) ) {
800 slap_op_t opidx = slap_req2op( op->o_tag );
802 if ( opidx == SLAP_OP_SEARCH ) {
803 if ( op->ors_tlimit <= 0 ) {
807 timeout = op->ors_tlimit;
808 timeout_err = LDAP_TIMELIMIT_EXCEEDED;
813 timeout = mt->mt_timeout[ opidx ];
817 /* better than nothing :) */
818 if ( timeout == 0 ) {
819 if ( mi->mi_idle_timeout ) {
820 timeout = mi->mi_idle_timeout;
826 stoptime = op->o_time + timeout;
829 LDAP_BACK_TV_SET( &tv );
832 rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
835 if ( timeout && slap_get_time() > stoptime ) {
836 (void)asyncmeta_back_cancel( mc, op, msgid, candidate );
837 rs->sr_err = timeout_err;
838 rs->sr_text = timeout_text;
842 LDAP_BACK_TV_SET( &tv );
843 ldap_pvt_thread_yield();
847 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE,
852 /* otherwise get the result; if it is not
853 * LDAP_SUCCESS, record it in the reply
854 * structure (this includes
855 * LDAP_COMPARE_{TRUE|FALSE}) */
857 /* only touch when activity actually took place... */
858 if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
859 msc->msc_time = op->o_time;
862 rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
863 &matched, &text, &refs, &ctrls, 1 );
865 if ( rc == LDAP_SUCCESS ) {
870 rs->sr_err = slap_map_api2result( rs );
872 /* RFC 4511: referrals can only appear
873 * if result code is LDAP_REFERRAL */
876 && refs[ 0 ][ 0 ] != '\0' )
878 if ( rs->sr_err != LDAP_REFERRAL ) {
879 Debug( LDAP_DEBUG_ANY,
880 "%s asyncmeta_back_op_result[%d]: "
881 "got referrals with err=%d\n",
883 candidate, rs->sr_err );
888 for ( i = 0; refs[ i ] != NULL; i++ )
890 rs->sr_ref = op->o_tmpalloc( sizeof( struct berval ) * ( i + 1 ),
892 for ( i = 0; refs[ i ] != NULL; i++ ) {
893 ber_str2bv( refs[ i ], 0, 0, &rs->sr_ref[ i ] );
895 BER_BVZERO( &rs->sr_ref[ i ] );
898 } else if ( rs->sr_err == LDAP_REFERRAL ) {
899 Debug( LDAP_DEBUG_ANY,
900 "%s asyncmeta_back_op_result[%d]: "
901 "got err=%d with null "
902 "or empty referrals\n",
904 candidate, rs->sr_err );
906 rs->sr_err = LDAP_NO_SUCH_OBJECT;
909 if ( ctrls != NULL ) {
910 rs->sr_ctrls = ctrls;
914 assert( res == NULL );
917 /* if the error in the reply structure is not
918 * LDAP_SUCCESS, try to map it from client
920 if ( !LDAP_ERR_OK( rs->sr_err ) ) {
921 rs->sr_err = slap_map_api2result( rs );
923 /* internal ops ( op->o_conn == NULL )
924 * must not reply to client */
925 if ( op->o_conn && !op->o_do_not_cache && matched ) {
927 /* record the (massaged) matched
928 * DN into the reply structure */
929 rs->sr_matched = matched;
933 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
934 asyncmeta_quarantine( op, mi, rs, candidate );
941 for ( i = 0; i < mi->mi_ntargets; i++ ) {
942 a_metasingleconn_t *msc = &mc->mc_conns[ i ];
944 char *xmatched = NULL;
946 if ( msc->msc_ld == NULL ) {
950 rs->sr_err = LDAP_SUCCESS;
952 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rs->sr_err );
953 if ( rs->sr_err != LDAP_SUCCESS ) {
955 * better check the type of error. In some cases
956 * (search ?) it might be better to return a
957 * success if at least one of the targets gave
958 * positive result ...
960 ldap_get_option( msc->msc_ld,
961 LDAP_OPT_DIAGNOSTIC_MESSAGE, &xtext );
962 if ( xtext != NULL && xtext [ 0 ] == '\0' ) {
963 ldap_memfree( xtext );
967 ldap_get_option( msc->msc_ld,
968 LDAP_OPT_MATCHED_DN, &xmatched );
969 if ( xmatched != NULL && xmatched[ 0 ] == '\0' ) {
970 ldap_memfree( xmatched );
974 rs->sr_err = slap_map_api2result( rs );
976 if ( LogTest( LDAP_DEBUG_ANY ) ) {
977 char buf[ SLAP_TEXT_BUFLEN ];
979 snprintf( buf, sizeof( buf ),
980 "asyncmeta_back_op_result[%d] "
981 "err=%d text=\"%s\" matched=\"%s\"",
983 ( xtext ? xtext : "" ),
984 ( xmatched ? xmatched : "" ) );
985 Debug( LDAP_DEBUG_ANY, "%s %s.\n",
986 op->o_log_prefix, buf, 0 );
990 * FIXME: need to rewrite "match" (need rwinfo)
992 switch ( rs->sr_err ) {
995 if ( xtext != NULL ) {
997 ldap_memfree( text );
1002 if ( xmatched != NULL ) {
1004 ldap_memfree( matched );
1013 ldap_memfree( xtext );
1017 ldap_memfree( xmatched );
1021 if ( META_BACK_TGT_QUARANTINE( mi->mi_targets[ i ] ) ) {
1022 asyncmeta_quarantine( op, mi, rs, i );
1026 if ( err != LDAP_SUCCESS ) {
1031 if ( matched != NULL ) {
1032 struct berval dn, pdn;
1034 ber_str2bv( matched, 0, 0, &dn );
1035 if ( dnPretty( NULL, &dn, &pdn, op->o_tmpmemctx ) == LDAP_SUCCESS ) {
1036 ldap_memfree( matched );
1037 matched_ctx = op->o_tmpmemctx;
1038 matched = pdn.bv_val;
1040 rs->sr_matched = matched;
1043 if ( rs->sr_err == LDAP_UNAVAILABLE ) {
1044 if ( !( sendok & LDAP_BACK_RETRYING ) ) {
1045 if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
1046 if ( rs->sr_text == NULL ) rs->sr_text = "Proxy operation retry failed";
1047 send_ldap_result( op, rs );
1051 } else if ( op->o_conn &&
1052 ( ( ( sendok & LDAP_BACK_SENDOK ) && LDAP_ERR_OK( rs->sr_err ) )
1053 || ( ( sendok & LDAP_BACK_SENDERR ) && !LDAP_ERR_OK( rs->sr_err ) ) ) )
1055 send_ldap_result( op, rs );
1058 op->o_tmpfree( (char *)rs->sr_matched, matched_ctx );
1061 ldap_memfree( text );
1064 op->o_tmpfree( rs->sr_ref, op->o_tmpmemctx );
1068 ber_memvfree( (void **)refs );
1071 assert( rs->sr_ctrls != NULL );
1072 ldap_controls_free( ctrls );
1075 rs->sr_text = save_text;
1076 rs->sr_matched = save_matched;
1077 rs->sr_ref = save_ref;
1078 rs->sr_ctrls = save_ctrls;
1080 return( LDAP_ERR_OK( rs->sr_err ) ? LDAP_SUCCESS : rs->sr_err );
1084 * meta_back_proxy_authz_cred()
1086 * prepares credentials & method for meta_back_proxy_authz_bind();
1087 * or, if method is SASL, performs the SASL bind directly.
1090 asyncmeta_back_proxy_authz_cred(
1095 ldap_back_send_t sendok,
1096 struct berval *binddn,
1097 struct berval *bindcred,
1100 a_metainfo_t *mi = mc->mc_info;
1101 a_metatarget_t *mt = mi->mi_targets[ candidate ];
1102 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1106 /* don't proxyAuthz if protocol is not LDAPv3 */
1107 switch ( mt->mt_version ) {
1112 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1118 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
1119 if ( sendok & LDAP_BACK_SENDERR ) {
1120 send_ldap_result( op, rs );
1122 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1126 if ( op->o_tag == LDAP_REQ_BIND ) {
1127 ndn = op->o_req_ndn;
1129 } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
1130 ndn = op->o_conn->c_ndn;
1135 rs->sr_err = LDAP_SUCCESS;
1138 * FIXME: we need to let clients use proxyAuthz
1139 * otherwise we cannot do symmetric pools of servers;
1140 * we have to live with the fact that a user can
1141 * authorize itself as any ID that is allowed
1142 * by the authzTo directive of the "proxyauthzdn".
1145 * NOTE: current Proxy Authorization specification
1146 * and implementation do not allow proxy authorization
1147 * control to be provided with Bind requests
1150 * if no bind took place yet, but the connection is bound
1151 * and the "proxyauthzdn" is set, then bind as
1152 * "proxyauthzdn" and explicitly add the proxyAuthz
1153 * control to every operation with the dn bound
1154 * to the connection as control value.
1157 /* bind as proxyauthzdn only if no idassert mode
1158 * is requested, or if the client's identity
1160 switch ( mt->mt_idassert_mode ) {
1161 case LDAP_BACK_IDASSERT_LEGACY:
1162 if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
1163 if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) )
1165 *binddn = mt->mt_idassert_authcDN;
1166 *bindcred = mt->mt_idassert_passwd;
1173 /* NOTE: rootdn can always idassert */
1174 if ( BER_BVISNULL( &ndn )
1175 && mt->mt_idassert_authz == NULL
1176 && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
1178 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1179 rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
1180 if ( sendok & LDAP_BACK_SENDERR ) {
1181 send_ldap_result( op, rs );
1183 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1188 rs->sr_err = LDAP_SUCCESS;
1189 *binddn = slap_empty_bv;
1190 *bindcred = slap_empty_bv;
1193 } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) {
1194 struct berval authcDN;
1196 if ( BER_BVISNULL( &ndn ) ) {
1197 authcDN = slap_empty_bv;
1202 rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz,
1203 &authcDN, &authcDN );
1204 if ( rs->sr_err != LDAP_SUCCESS ) {
1205 if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
1206 if ( sendok & LDAP_BACK_SENDERR ) {
1207 send_ldap_result( op, rs );
1209 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1213 rs->sr_err = LDAP_SUCCESS;
1214 *binddn = slap_empty_bv;
1215 *bindcred = slap_empty_bv;
1220 *binddn = mt->mt_idassert_authcDN;
1221 *bindcred = mt->mt_idassert_passwd;
1226 if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) {
1227 #ifdef HAVE_CYRUS_SASL
1228 void *defaults = NULL;
1229 struct berval authzID = BER_BVNULL;
1232 /* if SASL supports native authz, prepare for it */
1233 if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
1234 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
1236 switch ( mt->mt_idassert_mode ) {
1237 case LDAP_BACK_IDASSERT_OTHERID:
1238 case LDAP_BACK_IDASSERT_OTHERDN:
1239 authzID = mt->mt_idassert_authzID;
1242 case LDAP_BACK_IDASSERT_ANONYMOUS:
1243 BER_BVSTR( &authzID, "dn:" );
1246 case LDAP_BACK_IDASSERT_SELF:
1247 if ( BER_BVISNULL( &ndn ) ) {
1248 /* connection is not authc'd, so don't idassert */
1249 BER_BVSTR( &authzID, "dn:" );
1252 authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
1253 authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
1254 AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
1255 AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
1256 ndn.bv_val, ndn.bv_len + 1 );
1265 if ( mt->mt_idassert_secprops != NULL ) {
1266 rs->sr_err = ldap_set_option( msc->msc_ld,
1267 LDAP_OPT_X_SASL_SECPROPS,
1268 (void *)mt->mt_idassert_secprops );
1270 if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
1271 rs->sr_err = LDAP_OTHER;
1272 if ( sendok & LDAP_BACK_SENDERR ) {
1273 send_ldap_result( op, rs );
1275 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1280 defaults = lutil_sasl_defaults( msc->msc_ld,
1281 mt->mt_idassert_sasl_mech.bv_val,
1282 mt->mt_idassert_sasl_realm.bv_val,
1283 mt->mt_idassert_authcID.bv_val,
1284 mt->mt_idassert_passwd.bv_val,
1286 if ( defaults == NULL ) {
1287 rs->sr_err = LDAP_OTHER;
1288 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1289 if ( sendok & LDAP_BACK_SENDERR ) {
1290 send_ldap_result( op, rs );
1295 rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val,
1296 mt->mt_idassert_sasl_mech.bv_val, NULL, NULL,
1297 LDAP_SASL_QUIET, lutil_sasl_interact,
1300 rs->sr_err = slap_map_api2result( rs );
1301 if ( rs->sr_err != LDAP_SUCCESS ) {
1302 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1303 if ( sendok & LDAP_BACK_SENDERR ) {
1304 send_ldap_result( op, rs );
1308 LDAP_BACK_CONN_ISBOUND_SET( msc );
1311 lutil_sasl_freedefs( defaults );
1313 slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
1317 #endif /* HAVE_CYRUS_SASL */
1320 *method = mt->mt_idassert_authmethod;
1321 switch ( mt->mt_idassert_authmethod ) {
1322 case LDAP_AUTH_NONE:
1323 BER_BVSTR( binddn, "" );
1324 BER_BVSTR( bindcred, "" );
1327 case LDAP_AUTH_SIMPLE:
1332 LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
1333 rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
1334 if ( sendok & LDAP_BACK_SENDERR ) {
1335 send_ldap_result( op, rs );
1342 if ( !BER_BVISEMPTY( binddn ) ) {
1343 LDAP_BACK_CONN_ISIDASSERT_SET( msc );
1350 asyncmeta_proxy_authz_bind(
1355 ldap_back_send_t sendok,
1358 a_metainfo_t *mi = mc->mc_info;
1359 a_metatarget_t *mt = mi->mi_targets[ candidate ];
1360 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1361 struct berval binddn = BER_BVC( "" ),
1362 cred = BER_BVC( "" );
1363 int method = LDAP_AUTH_NONE,
1366 rc = asyncmeta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
1367 if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
1371 case LDAP_AUTH_NONE:
1372 case LDAP_AUTH_SIMPLE:
1374 rs->sr_err = ldap_sasl_bind( msc->msc_ld,
1375 binddn.bv_val, LDAP_SASL_SIMPLE,
1376 &cred, NULL, NULL, &msgid );
1377 if ( rs->sr_err != LDAP_X_CONNECTING ) {
1380 ldap_pvt_thread_yield();
1383 rc = asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
1384 if ( rc == LDAP_SUCCESS ) {
1385 /* set rebind stuff in case of successful proxyAuthz bind,
1386 * so that referral chasing is attempted using the right
1388 LDAP_BACK_CONN_ISBOUND_SET( msc );
1389 ber_bvreplace( &msc->msc_bound_ndn, &binddn );
1391 if ( META_BACK_TGT_SAVECRED( mt ) ) {
1392 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
1393 memset( msc->msc_cred.bv_val, 0,
1394 msc->msc_cred.bv_len );
1396 ber_bvreplace( &msc->msc_cred, &cred );
1397 ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
1408 return LDAP_BACK_CONN_ISBOUND( msc );
1414 * if any needs to be added, it is prepended to existing ones,
1415 * in a newly allocated array. The companion function
1416 * mi->mi_ldap_extra->controls_free() must be used to restore the original
1417 * status of op->o_ctrls.
1420 asyncmeta_controls_add(
1425 LDAPControl ***pctrls )
1427 a_metainfo_t *mi = mc->mc_info;
1428 a_metatarget_t *mt = mi->mi_targets[ candidate ];
1429 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1431 LDAPControl **ctrls = NULL;
1432 /* set to the maximum number of controls this backend can add */
1433 LDAPControl c[ 2 ] = {{ 0 }};
1434 int n = 0, i, j1 = 0, j2 = 0;
1438 rs->sr_err = LDAP_SUCCESS;
1440 /* don't add controls if protocol is not LDAPv3 */
1441 switch ( mt->mt_version ) {
1446 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1455 /* put controls that go __before__ existing ones here */
1457 /* proxyAuthz for identity assertion */
1458 switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
1459 mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
1461 case SLAP_CB_CONTINUE:
1472 /* put controls that go __after__ existing ones here */
1474 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1475 /* session tracking */
1476 if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
1477 switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
1478 case SLAP_CB_CONTINUE:
1489 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1491 if ( rs->sr_err == SLAP_CB_CONTINUE ) {
1492 rs->sr_err = LDAP_SUCCESS;
1495 /* if nothing to do, just bail out */
1496 if ( j1 == 0 && j2 == 0 ) {
1500 assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
1502 if ( op->o_ctrls ) {
1503 for ( n = 0; op->o_ctrls[ n ]; n++ )
1504 /* just count ctrls */ ;
1507 ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
1510 ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
1511 *ctrls[ 0 ] = c[ 0 ];
1512 for ( i = 1; i < j1; i++ ) {
1513 ctrls[ i ] = &ctrls[ 0 ][ i ];
1514 *ctrls[ i ] = c[ i ];
1519 if ( op->o_ctrls ) {
1520 for ( i = 0; op->o_ctrls[ i ]; i++ ) {
1521 ctrls[ i + j1 ] = op->o_ctrls[ i ];
1527 ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
1528 *ctrls[ n ] = c[ j1 ];
1529 for ( i = 1; i < j2; i++ ) {
1530 ctrls[ n + i ] = &ctrls[ n ][ i ];
1531 *ctrls[ n + i ] = c[ i ];
1535 ctrls[ n + j2 ] = NULL;
1538 if ( ctrls == NULL ) {
1539 ctrls = op->o_ctrls;
1551 * same as asyncmeta_controls_add, but creates a new controls array
1552 * to be used by the operation copy
1555 asyncmeta_controls_add_copy(
1560 LDAPControl ***pctrls )
1562 a_metainfo_t *mi = (a_metainfo_t *)op->o_bd->be_private;
1563 a_metatarget_t *mt = mi->mi_targets[ candidate ];
1564 a_metasingleconn_t *msc = mc->mc_conns[ candidate ];
1566 LDAPControl **ctrls = NULL;
1567 /* set to the maximum number of controls this backend can add */
1568 LDAPControl c[ 2 ] = {{ 0 }};
1569 int n = 0, i, j1 = 0, j2 = 0;
1573 rs->sr_err = LDAP_SUCCESS;
1575 /* don't add controls if protocol is not LDAPv3 */
1576 switch ( mt->mt_version ) {
1581 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
1590 /* put controls that go __before__ existing ones here */
1592 /* proxyAuthz for identity assertion */
1593 switch ( mi->mi_ldap_extra->proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
1594 mt->mt_version, &mt->mt_idassert, &c[ j1 ] ) )
1596 case SLAP_CB_CONTINUE:
1607 /* put controls that go __after__ existing ones here */
1609 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1610 /* session tracking */
1611 if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
1612 switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
1613 case SLAP_CB_CONTINUE:
1624 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1626 if ( rs->sr_err == SLAP_CB_CONTINUE ) {
1627 rs->sr_err = LDAP_SUCCESS;
1631 if ( op->o_ctrls ) {
1632 for ( n = 0; op->o_ctrls[ n ]; n++ )
1633 /* just count ctrls */ ;
1636 ctrls = ch_calloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ));
1638 ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
1639 *ctrls[ 0 ] = c[ 0 ];
1640 for ( i = 1; i < j1; i++ ) {
1641 ctrls[ i ] = &ctrls[ 0 ][ i ];
1642 *ctrls[ i ] = c[ i ];
1647 if ( op->o_ctrls ) {
1648 for ( i = 0; op->o_ctrls[ i ]; i++ ) {
1649 ctrls[ i + j1 ] = op->o_ctrls[ i ];
1655 ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
1656 *ctrls[ n ] = c[ j1 ];
1657 for ( i = 1; i < j2; i++ ) {
1658 ctrls[ n + i ] = &ctrls[ n ][ i ];
1659 *ctrls[ n + i ] = c[ i ];
1663 ctrls[ n + j2 ] = NULL;
1667 op->o_ctrls = ctrls;
1674 * asyncmeta_dobind_init()
1676 * initiates bind for a candidate target
1678 meta_search_candidate_t
1679 asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
1681 SlapReply *candidates = bc->candidates;
1682 a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info;
1683 a_metatarget_t *mt = mi->mi_targets[ candidate ];
1684 a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
1686 struct berval binddn = msc->msc_bound_ndn,
1687 cred = msc->msc_cred;
1693 meta_search_candidate_t retcode;
1695 Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_search_dobind_init[%d]\n",
1696 op->o_log_prefix, candidate, 0 );
1698 if ( mc->mc_authz_target == META_BOUND_ALL ) {
1699 return META_SEARCH_CANDIDATE;
1702 retcode = META_SEARCH_BINDING;
1703 if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
1704 /* already bound (or anonymous) */
1707 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
1710 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
1714 snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
1715 (void *)mc, (void *)msc->msc_ld,
1716 bound ? " bound" : " anonymous",
1717 bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
1718 Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
1719 op->o_log_prefix, candidate, buf );
1720 #endif /* DEBUG_205 */
1722 retcode = META_SEARCH_CANDIDATE;
1724 } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
1725 /* another thread is binding the target for this conn; wait */
1728 char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
1730 snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
1731 (void *)mc, (void *)msc->msc_ld );
1732 Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
1733 op->o_log_prefix, candidate, buf );
1734 #endif /* DEBUG_205 */
1736 candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
1737 retcode = META_SEARCH_NEED_BIND;
1740 /* we'll need to bind the target for this conn */
1743 char buf[ SLAP_TEXT_BUFLEN ];
1745 snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
1746 (void *)mc, (void *)msc->msc_ld );
1747 Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_search_dobind_init[%d]%s\n",
1748 op->o_log_prefix, candidate, buf );
1749 #endif /* DEBUG_205 */
1751 if ( msc->msc_ld == NULL ) {
1752 /* for some reason (e.g. because formerly in "binding"
1753 * state, with eventual connection expiration or invalidation)
1754 * it was not initialized as expected */
1756 Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p ld=NULL\n",
1757 op->o_log_prefix, candidate, (void *)mc );
1759 rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
1760 LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
1763 assert( msc->msc_ld != NULL );
1766 case LDAP_SERVER_DOWN:
1767 case LDAP_UNAVAILABLE:
1775 LDAP_BACK_CONN_BINDING_SET( msc );
1778 if ( retcode != META_SEARCH_BINDING ) {
1782 if ( op->o_conn != NULL &&
1783 !op->o_do_not_cache &&
1784 ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
1785 BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
1786 ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
1788 rc = asyncmeta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
1792 case LDAP_UNAVAILABLE:
1798 /* NOTE: we copy things here, even if bind didn't succeed yet,
1799 * because the connection is not shared until bind is over */
1800 if ( !BER_BVISNULL( &binddn ) ) {
1801 ldap_pvt_thread_mutex_lock(&mc->mc_om_mutex);
1803 ber_bvreplace( &msc->msc_bound_ndn, &binddn );
1804 if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
1805 if ( !BER_BVISNULL( &msc->msc_cred ) ) {
1806 memset( msc->msc_cred.bv_val, 0,
1807 msc->msc_cred.bv_len );
1809 ber_bvreplace( &msc->msc_cred, &cred );
1811 ldap_pvt_thread_mutex_unlock(&mc->mc_om_mutex);
1813 if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
1814 /* apparently, idassert was configured with SASL bind,
1815 * so bind occurred inside meta_back_proxy_authz_cred() */
1816 LDAP_BACK_CONN_BINDING_CLEAR( msc );
1817 return META_SEARCH_CANDIDATE;
1822 case LDAP_AUTH_NONE:
1823 case LDAP_AUTH_SIMPLE:
1824 /* do a simple bind with binddn, cred */
1833 assert( msc->msc_ld != NULL );
1835 if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
1836 /* bind anonymously? */
1837 Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
1838 "non-empty dn with empty cred; binding anonymously\n",
1839 op->o_log_prefix, candidate, (void *)mc );
1840 cred = slap_empty_bv;
1842 } else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
1844 Debug( LDAP_DEBUG_ANY, "%s asyncmeta_search_dobind_init[%d] mc=%p: "
1845 "empty dn with non-empty cred: error\n",
1846 op->o_log_prefix, candidate, (void *)mc );
1851 rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
1852 NULL, NULL, &msgid );
1853 ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rc );
1855 if (rc == LDAP_SERVER_DOWN ) {
1858 candidates[ candidate ].sr_msgid = msgid;
1859 asyncmeta_set_msc_time(msc);
1862 char buf[ SLAP_TEXT_BUFLEN ];
1864 snprintf( buf, sizeof( buf ), "asyncmeta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
1865 candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
1866 Debug( LDAP_DEBUG_ANY, "### %s %s\n",
1867 op->o_log_prefix, buf, 0 );
1869 #endif /* DEBUG_205 */
1873 assert( msgid >= 0 );
1874 META_BINDING_SET( &candidates[ candidate ] );
1875 rs->sr_err = LDAP_SUCCESS;
1876 return META_SEARCH_BINDING;
1878 case LDAP_X_CONNECTING:
1879 /* must retry, same conn */
1880 candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
1881 LDAP_BACK_CONN_BINDING_CLEAR( msc );
1884 case LDAP_SERVER_DOWN:
1886 retcode = META_SEARCH_ERR;
1887 rs->sr_err = LDAP_UNAVAILABLE;
1888 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
1896 rc = slap_map_api2result( rs );
1897 candidates[ candidate ].sr_err = rc;
1898 if ( META_BACK_ONERR_STOP( mi ) ) {
1899 retcode = META_SEARCH_ERR;
1902 retcode = META_SEARCH_NOT_CANDIDATE;
1904 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
1914 meta_search_candidate_t
1915 asyncmeta_dobind_init_with_retry(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
1918 int rc, retries = 1;
1919 a_metasingleconn_t *msc = &mc->mc_conns[candidate];
1920 a_metainfo_t *mi = mc->mc_info;
1921 a_metatarget_t *mt = mi->mi_targets[ candidate ];
1922 SlapReply *candidates = bc->candidates;
1925 rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
1926 if (rs->sr_err != LDAP_UNAVAILABLE) {
1928 } else if (retries <= 0) {
1929 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1930 if (mc->mc_active < 1) {
1931 asyncmeta_clear_one_msc(NULL, mc, candidate);
1933 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1938 if ( LogTest( LDAP_DEBUG_ANY ) ) {
1939 char buf[ SLAP_TEXT_BUFLEN ];
1941 /* this lock is required; however,
1942 * it's invoked only when logging is on */
1943 ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
1944 snprintf( buf, sizeof( buf ),
1945 "retrying URI=\"%s\" DN=\"%s\"",
1947 BER_BVISNULL( &msc->msc_bound_ndn ) ?
1948 "" : msc->msc_bound_ndn.bv_val );
1949 ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
1951 Debug( LDAP_DEBUG_ANY,
1952 "%s asyncmeta_search_dobind_init_with_retry[%d]: %s.\n",
1953 op->o_log_prefix, candidate, buf );
1956 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1957 if (mc->mc_active < 1) {
1958 asyncmeta_clear_one_msc(NULL, mc, candidate);
1960 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1962 ( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );
1964 rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
1965 LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
1967 if (rs->sr_err != LDAP_SUCCESS) {
1968 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
1969 if (mc->mc_active < 1) {
1970 asyncmeta_clear_one_msc(NULL, mc, candidate);
1972 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
1973 return META_SEARCH_ERR;