1*cf1d77f7Schristos /* $NetBSD: bind.c,v 1.2 2021/08/14 16:14:59 christos Exp $ */
292cfeba6Schristos
392cfeba6Schristos /* bind.c - bind request handler functions for binding
492cfeba6Schristos * to remote targets for back-asyncmeta */
592cfeba6Schristos /* $OpenLDAP$ */
692cfeba6Schristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
792cfeba6Schristos *
892cfeba6Schristos * Copyright 2016-2021 The OpenLDAP Foundation.
992cfeba6Schristos * Portions Copyright 2016 Symas Corporation.
1092cfeba6Schristos * All rights reserved.
1192cfeba6Schristos *
1292cfeba6Schristos * Redistribution and use in source and binary forms, with or without
1392cfeba6Schristos * modification, are permitted only as authorized by the OpenLDAP
1492cfeba6Schristos * Public License.
1592cfeba6Schristos *
1692cfeba6Schristos * A copy of this license is available in the file LICENSE in the
1792cfeba6Schristos * top-level directory of the distribution or, alternatively, at
1892cfeba6Schristos * <http://www.OpenLDAP.org/license.html>.
1992cfeba6Schristos */
2092cfeba6Schristos
2192cfeba6Schristos /* ACKNOWLEDGEMENTS:
2292cfeba6Schristos * This work was developed by Symas Corporation
2392cfeba6Schristos * based on back-meta module for inclusion in OpenLDAP Software.
2492cfeba6Schristos * This work was sponsored by Ericsson. */
2592cfeba6Schristos
2692cfeba6Schristos #include <sys/cdefs.h>
27*cf1d77f7Schristos __RCSID("$NetBSD: bind.c,v 1.2 2021/08/14 16:14:59 christos Exp $");
2892cfeba6Schristos
2992cfeba6Schristos #include "portable.h"
3092cfeba6Schristos
3192cfeba6Schristos #include <stdio.h>
3292cfeba6Schristos
3392cfeba6Schristos #include <ac/errno.h>
3492cfeba6Schristos #include <ac/socket.h>
3592cfeba6Schristos #include <ac/string.h>
3692cfeba6Schristos #include "slap.h"
3792cfeba6Schristos #include "../../../libraries/libldap/ldap-int.h"
3892cfeba6Schristos
3992cfeba6Schristos #define AVL_INTERNAL
4092cfeba6Schristos #include "../back-ldap/back-ldap.h"
4192cfeba6Schristos #include "back-asyncmeta.h"
4292cfeba6Schristos #include "lutil_ldap.h"
4392cfeba6Schristos
4492cfeba6Schristos #define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ "2.16.840.1.113730.3.4.12"
4592cfeba6Schristos
4692cfeba6Schristos static int
4792cfeba6Schristos asyncmeta_proxy_authz_bind(
4892cfeba6Schristos a_metaconn_t *mc,
4992cfeba6Schristos int candidate,
5092cfeba6Schristos Operation *op,
5192cfeba6Schristos SlapReply *rs,
5292cfeba6Schristos ldap_back_send_t sendok,
5392cfeba6Schristos int dolock );
5492cfeba6Schristos
5592cfeba6Schristos static int
5692cfeba6Schristos asyncmeta_single_bind(
5792cfeba6Schristos Operation *op,
5892cfeba6Schristos SlapReply *rs,
5992cfeba6Schristos a_metaconn_t *mc,
6092cfeba6Schristos int candidate );
6192cfeba6Schristos
6292cfeba6Schristos int
asyncmeta_back_bind(Operation * op,SlapReply * rs)6392cfeba6Schristos asyncmeta_back_bind( Operation *op, SlapReply *rs )
6492cfeba6Schristos {
6592cfeba6Schristos a_metainfo_t *mi = ( a_metainfo_t * )op->o_bd->be_private;
6692cfeba6Schristos a_metaconn_t *mc = NULL;
6792cfeba6Schristos
6892cfeba6Schristos int rc = LDAP_OTHER,
6992cfeba6Schristos i,
7092cfeba6Schristos gotit = 0,
7192cfeba6Schristos isroot = 0;
7292cfeba6Schristos
7392cfeba6Schristos SlapReply *candidates;
7492cfeba6Schristos
7592cfeba6Schristos candidates = op->o_tmpcalloc(mi->mi_ntargets, sizeof(SlapReply),op->o_tmpmemctx);
7692cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
7792cfeba6Schristos
7892cfeba6Schristos Debug( LDAP_DEBUG_ARGS, "%s asyncmeta_back_bind: dn=\"%s\".\n",
7992cfeba6Schristos op->o_log_prefix, op->o_req_dn.bv_val );
8092cfeba6Schristos
8192cfeba6Schristos /* the test on the bind method should be superfluous */
8292cfeba6Schristos switch ( be_rootdn_bind( op, rs ) ) {
8392cfeba6Schristos case LDAP_SUCCESS:
8492cfeba6Schristos if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
8592cfeba6Schristos /* frontend will return success */
8692cfeba6Schristos return rs->sr_err;
8792cfeba6Schristos }
8892cfeba6Schristos
8992cfeba6Schristos isroot = 1;
9092cfeba6Schristos /* fallthru */
9192cfeba6Schristos
9292cfeba6Schristos case SLAP_CB_CONTINUE:
9392cfeba6Schristos break;
9492cfeba6Schristos
9592cfeba6Schristos default:
9692cfeba6Schristos /* be_rootdn_bind() sent result */
9792cfeba6Schristos return rs->sr_err;
9892cfeba6Schristos }
9992cfeba6Schristos
10092cfeba6Schristos /* we need asyncmeta_getconn() not send result even on error,
10192cfeba6Schristos * because we want to intercept the error and make it
10292cfeba6Schristos * invalidCredentials */
10392cfeba6Schristos mc = asyncmeta_getconn( op, rs, candidates, NULL, LDAP_BACK_BIND_DONTSEND, 1 );
10492cfeba6Schristos if ( !mc ) {
10592cfeba6Schristos Debug(LDAP_DEBUG_ANY,
10692cfeba6Schristos "%s asyncmeta_back_bind: no target " "for dn \"%s\" (%d%s%s).\n",
10792cfeba6Schristos op->o_log_prefix, op->o_req_dn.bv_val,
10892cfeba6Schristos rs->sr_err, rs->sr_text ? ". " : "",
10992cfeba6Schristos rs->sr_text ? rs->sr_text : "" );
11092cfeba6Schristos
11192cfeba6Schristos /* FIXME: there might be cases where we don't want
11292cfeba6Schristos * to map the error onto invalidCredentials */
11392cfeba6Schristos switch ( rs->sr_err ) {
11492cfeba6Schristos case LDAP_NO_SUCH_OBJECT:
11592cfeba6Schristos case LDAP_UNWILLING_TO_PERFORM:
11692cfeba6Schristos rs->sr_err = LDAP_INVALID_CREDENTIALS;
11792cfeba6Schristos rs->sr_text = NULL;
11892cfeba6Schristos break;
11992cfeba6Schristos }
12092cfeba6Schristos send_ldap_result( op, rs );
12192cfeba6Schristos return rs->sr_err;
12292cfeba6Schristos }
12392cfeba6Schristos
12492cfeba6Schristos /*
12592cfeba6Schristos * Each target is scanned ...
12692cfeba6Schristos */
12792cfeba6Schristos mc->mc_authz_target = META_BOUND_NONE;
12892cfeba6Schristos for ( i = 0; i < mi->mi_ntargets; i++ ) {
12992cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ i ];
13092cfeba6Schristos int lerr;
13192cfeba6Schristos
13292cfeba6Schristos /*
13392cfeba6Schristos * Skip non-candidates
13492cfeba6Schristos */
13592cfeba6Schristos if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
13692cfeba6Schristos continue;
13792cfeba6Schristos }
13892cfeba6Schristos
13992cfeba6Schristos if ( gotit == 0 ) {
14092cfeba6Schristos /* set rc to LDAP_SUCCESS only if at least
14192cfeba6Schristos * one candidate has been tried */
14292cfeba6Schristos rc = LDAP_SUCCESS;
14392cfeba6Schristos gotit = 1;
14492cfeba6Schristos
14592cfeba6Schristos } else if ( !isroot ) {
14692cfeba6Schristos /*
14792cfeba6Schristos * A bind operation is expected to have
14892cfeba6Schristos * ONE CANDIDATE ONLY!
14992cfeba6Schristos */
15092cfeba6Schristos Debug( LDAP_DEBUG_ANY,
15192cfeba6Schristos "### %s asyncmeta_back_bind: more than one"
15292cfeba6Schristos " candidate selected...\n",
15392cfeba6Schristos op->o_log_prefix );
15492cfeba6Schristos }
15592cfeba6Schristos
15692cfeba6Schristos if ( isroot ) {
15792cfeba6Schristos if ( mt->mt_idassert_authmethod == LDAP_AUTH_NONE
15892cfeba6Schristos || BER_BVISNULL( &mt->mt_idassert_authcDN ) )
15992cfeba6Schristos {
16092cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ i ];
16192cfeba6Schristos
16292cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
16392cfeba6Schristos ch_free( msc->msc_bound_ndn.bv_val );
16492cfeba6Schristos BER_BVZERO( &msc->msc_bound_ndn );
16592cfeba6Schristos }
16692cfeba6Schristos
16792cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_cred ) ) {
16892cfeba6Schristos /* destroy sensitive data */
16992cfeba6Schristos memset( msc->msc_cred.bv_val, 0,
17092cfeba6Schristos msc->msc_cred.bv_len );
17192cfeba6Schristos ch_free( msc->msc_cred.bv_val );
17292cfeba6Schristos BER_BVZERO( &msc->msc_cred );
17392cfeba6Schristos }
17492cfeba6Schristos
17592cfeba6Schristos continue;
17692cfeba6Schristos }
17792cfeba6Schristos
17892cfeba6Schristos
17992cfeba6Schristos (void)asyncmeta_proxy_authz_bind( mc, i, op, rs, LDAP_BACK_DONTSEND, 1 );
18092cfeba6Schristos lerr = rs->sr_err;
18192cfeba6Schristos
18292cfeba6Schristos } else {
18392cfeba6Schristos lerr = asyncmeta_single_bind( op, rs, mc, i );
18492cfeba6Schristos }
18592cfeba6Schristos
18692cfeba6Schristos if ( lerr != LDAP_SUCCESS ) {
18792cfeba6Schristos rc = rs->sr_err = lerr;
18892cfeba6Schristos
18992cfeba6Schristos /* FIXME: in some cases (e.g. unavailable)
19092cfeba6Schristos * do not assume it's not candidate; rather
19192cfeba6Schristos * mark this as an error to be eventually
19292cfeba6Schristos * reported to client */
19392cfeba6Schristos META_CANDIDATE_CLEAR( &candidates[ i ] );
19492cfeba6Schristos break;
19592cfeba6Schristos }
19692cfeba6Schristos }
19792cfeba6Schristos
19892cfeba6Schristos if ( mc != NULL ) {
19992cfeba6Schristos for ( i = 0; i < mi->mi_ntargets; i++ ) {
20092cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ i ];
20192cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
20292cfeba6Schristos ch_free( msc->msc_bound_ndn.bv_val );
20392cfeba6Schristos }
20492cfeba6Schristos
20592cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_cred ) ) {
20692cfeba6Schristos /* destroy sensitive data */
20792cfeba6Schristos memset( msc->msc_cred.bv_val, 0,
20892cfeba6Schristos msc->msc_cred.bv_len );
20992cfeba6Schristos ch_free( msc->msc_cred.bv_val );
21092cfeba6Schristos }
21192cfeba6Schristos }
21292cfeba6Schristos asyncmeta_back_conn_free( mc );
21392cfeba6Schristos }
21492cfeba6Schristos
21592cfeba6Schristos /*
21692cfeba6Schristos * rc is LDAP_SUCCESS if at least one bind succeeded,
21792cfeba6Schristos * err is the last error that occurred during a bind;
21892cfeba6Schristos * if at least (and at most?) one bind succeeds, fine.
21992cfeba6Schristos */
22092cfeba6Schristos if ( rc != LDAP_SUCCESS ) {
22192cfeba6Schristos
22292cfeba6Schristos /*
22392cfeba6Schristos * deal with bind failure ...
22492cfeba6Schristos */
22592cfeba6Schristos
22692cfeba6Schristos /*
22792cfeba6Schristos * no target was found within the naming context,
22892cfeba6Schristos * so bind must fail with invalid credentials
22992cfeba6Schristos */
23092cfeba6Schristos if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
23192cfeba6Schristos rs->sr_err = LDAP_INVALID_CREDENTIALS;
23292cfeba6Schristos } else {
23392cfeba6Schristos rs->sr_err = slap_map_api2result( rs );
23492cfeba6Schristos }
23592cfeba6Schristos send_ldap_result( op, rs );
23692cfeba6Schristos return rs->sr_err;
23792cfeba6Schristos
23892cfeba6Schristos }
23992cfeba6Schristos return LDAP_SUCCESS;
24092cfeba6Schristos }
24192cfeba6Schristos
24292cfeba6Schristos static int
asyncmeta_bind_op_result(Operation * op,SlapReply * rs,a_metaconn_t * mc,int candidate,int msgid,ldap_back_send_t sendok,int dolock)24392cfeba6Schristos asyncmeta_bind_op_result(
24492cfeba6Schristos Operation *op,
24592cfeba6Schristos SlapReply *rs,
24692cfeba6Schristos a_metaconn_t *mc,
24792cfeba6Schristos int candidate,
24892cfeba6Schristos int msgid,
24992cfeba6Schristos ldap_back_send_t sendok,
25092cfeba6Schristos int dolock )
25192cfeba6Schristos {
25292cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
25392cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
25492cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
25592cfeba6Schristos LDAPMessage *res;
25692cfeba6Schristos struct timeval tv;
25792cfeba6Schristos int rc;
25892cfeba6Schristos int nretries = mt->mt_nretries;
25992cfeba6Schristos
26092cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
26192cfeba6Schristos ">>> %s asyncmeta_bind_op_result[%d]\n",
26292cfeba6Schristos op->o_log_prefix, candidate );
26392cfeba6Schristos
26492cfeba6Schristos /* make sure this is clean */
26592cfeba6Schristos assert( rs->sr_ctrls == NULL );
26692cfeba6Schristos
26792cfeba6Schristos if ( rs->sr_err == LDAP_SUCCESS ) {
26892cfeba6Schristos time_t stoptime = (time_t)(-1),
26992cfeba6Schristos timeout;
27092cfeba6Schristos int timeout_err = op->o_protocol >= LDAP_VERSION3 ?
27192cfeba6Schristos LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
27292cfeba6Schristos const char *timeout_text = "Operation timed out";
27392cfeba6Schristos slap_op_t opidx = slap_req2op( op->o_tag );
27492cfeba6Schristos
27592cfeba6Schristos /* since timeout is not specified, compute and use
27692cfeba6Schristos * the one specific to the ongoing operation */
27792cfeba6Schristos if ( opidx == LDAP_REQ_SEARCH ) {
27892cfeba6Schristos if ( op->ors_tlimit <= 0 ) {
27992cfeba6Schristos timeout = 0;
28092cfeba6Schristos
28192cfeba6Schristos } else {
28292cfeba6Schristos timeout = op->ors_tlimit;
28392cfeba6Schristos timeout_err = LDAP_TIMELIMIT_EXCEEDED;
28492cfeba6Schristos timeout_text = NULL;
28592cfeba6Schristos }
28692cfeba6Schristos
28792cfeba6Schristos } else {
28892cfeba6Schristos timeout = mt->mt_timeout[ opidx ];
28992cfeba6Schristos }
29092cfeba6Schristos
29192cfeba6Schristos /* better than nothing :) */
29292cfeba6Schristos if ( timeout == 0 ) {
29392cfeba6Schristos if ( mi->mi_idle_timeout ) {
29492cfeba6Schristos timeout = mi->mi_idle_timeout;
29592cfeba6Schristos
29692cfeba6Schristos }
29792cfeba6Schristos }
29892cfeba6Schristos
29992cfeba6Schristos if ( timeout ) {
30092cfeba6Schristos stoptime = op->o_time + timeout;
30192cfeba6Schristos }
30292cfeba6Schristos
30392cfeba6Schristos LDAP_BACK_TV_SET( &tv );
30492cfeba6Schristos
30592cfeba6Schristos /*
30692cfeba6Schristos * handle response!!!
30792cfeba6Schristos */
30892cfeba6Schristos retry:;
30992cfeba6Schristos rc = ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
31092cfeba6Schristos switch ( rc ) {
31192cfeba6Schristos case 0:
31292cfeba6Schristos if ( nretries != META_RETRY_NEVER
31392cfeba6Schristos || ( timeout && slap_get_time() <= stoptime ) )
31492cfeba6Schristos {
31592cfeba6Schristos ldap_pvt_thread_yield();
31692cfeba6Schristos if ( nretries > 0 ) {
31792cfeba6Schristos nretries--;
31892cfeba6Schristos }
31992cfeba6Schristos tv = mt->mt_bind_timeout;
32092cfeba6Schristos goto retry;
32192cfeba6Schristos }
32292cfeba6Schristos
32392cfeba6Schristos /* don't let anyone else use this handler,
32492cfeba6Schristos * because there's a pending bind that will not
32592cfeba6Schristos * be acknowledged */
32692cfeba6Schristos assert( LDAP_BACK_CONN_BINDING( msc ) );
32792cfeba6Schristos
32892cfeba6Schristos #ifdef DEBUG_205
32992cfeba6Schristos Debug( LDAP_DEBUG_ANY, "### %s asyncmeta_bind_op_result ldap_unbind_ext[%d] ld=%p\n",
33092cfeba6Schristos op->o_log_prefix, candidate, (void *)msc->msc_ld );
33192cfeba6Schristos #endif /* DEBUG_205 */
33292cfeba6Schristos
33392cfeba6Schristos rs->sr_err = timeout_err;
33492cfeba6Schristos rs->sr_text = timeout_text;
33592cfeba6Schristos break;
33692cfeba6Schristos
33792cfeba6Schristos case -1:
33892cfeba6Schristos ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
33992cfeba6Schristos &rs->sr_err );
34092cfeba6Schristos
34192cfeba6Schristos Debug( LDAP_DEBUG_ANY,
34292cfeba6Schristos "### %s asyncmeta_bind_op_result[%d]: err=%d (%s) nretries=%d.\n",
34392cfeba6Schristos op->o_log_prefix, candidate, rs->sr_err,
34492cfeba6Schristos ldap_err2string(rs->sr_err), nretries );
34592cfeba6Schristos break;
34692cfeba6Schristos
34792cfeba6Schristos default:
34892cfeba6Schristos /* only touch when activity actually took place... */
34992cfeba6Schristos if ( mi->mi_idle_timeout != 0 && msc->msc_time < op->o_time ) {
35092cfeba6Schristos msc->msc_time = op->o_time;
35192cfeba6Schristos }
35292cfeba6Schristos
35392cfeba6Schristos /* FIXME: matched? referrals? response controls? */
35492cfeba6Schristos rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
35592cfeba6Schristos NULL, NULL, NULL, NULL, 1 );
35692cfeba6Schristos if ( rc != LDAP_SUCCESS ) {
35792cfeba6Schristos rs->sr_err = rc;
35892cfeba6Schristos }
35992cfeba6Schristos rs->sr_err = slap_map_api2result( rs );
36092cfeba6Schristos break;
36192cfeba6Schristos }
36292cfeba6Schristos }
36392cfeba6Schristos
36492cfeba6Schristos rs->sr_err = slap_map_api2result( rs );
36592cfeba6Schristos Debug( LDAP_DEBUG_TRACE,
36692cfeba6Schristos "<<< %s asyncmeta_bind_op_result[%d] err=%d\n",
36792cfeba6Schristos op->o_log_prefix, candidate, rs->sr_err );
36892cfeba6Schristos
36992cfeba6Schristos return rs->sr_err;
37092cfeba6Schristos }
37192cfeba6Schristos
37292cfeba6Schristos /*
37392cfeba6Schristos * asyncmeta_single_bind
37492cfeba6Schristos *
37592cfeba6Schristos * attempts to perform a bind with creds
37692cfeba6Schristos */
37792cfeba6Schristos static int
asyncmeta_single_bind(Operation * op,SlapReply * rs,a_metaconn_t * mc,int candidate)37892cfeba6Schristos asyncmeta_single_bind(
37992cfeba6Schristos Operation *op,
38092cfeba6Schristos SlapReply *rs,
38192cfeba6Schristos a_metaconn_t *mc,
38292cfeba6Schristos int candidate )
38392cfeba6Schristos {
38492cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
38592cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
38692cfeba6Schristos struct berval mdn = BER_BVNULL;
38792cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
38892cfeba6Schristos int msgid;
38992cfeba6Schristos a_dncookie dc;
39092cfeba6Schristos struct berval save_o_dn;
39192cfeba6Schristos int save_o_do_not_cache;
39292cfeba6Schristos LDAPControl **ctrls = NULL;
39392cfeba6Schristos
39492cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
39592cfeba6Schristos ch_free( msc->msc_bound_ndn.bv_val );
39692cfeba6Schristos BER_BVZERO( &msc->msc_bound_ndn );
39792cfeba6Schristos }
39892cfeba6Schristos
39992cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_cred ) ) {
40092cfeba6Schristos /* destroy sensitive data */
40192cfeba6Schristos memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
40292cfeba6Schristos ch_free( msc->msc_cred.bv_val );
40392cfeba6Schristos BER_BVZERO( &msc->msc_cred );
40492cfeba6Schristos }
40592cfeba6Schristos
40692cfeba6Schristos /*
40792cfeba6Schristos * Rewrite the bind dn if needed
40892cfeba6Schristos */
40992cfeba6Schristos dc.op = op;
41092cfeba6Schristos dc.target = mt;
41192cfeba6Schristos dc.memctx = op->o_tmpmemctx;
41292cfeba6Schristos dc.to_from = MASSAGE_REQ;
41392cfeba6Schristos
41492cfeba6Schristos asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn );
41592cfeba6Schristos
41692cfeba6Schristos /* don't add proxyAuthz; set the bindDN */
41792cfeba6Schristos save_o_dn = op->o_dn;
41892cfeba6Schristos save_o_do_not_cache = op->o_do_not_cache;
41992cfeba6Schristos op->o_do_not_cache = 1;
42092cfeba6Schristos op->o_dn = op->o_req_dn;
42192cfeba6Schristos
42292cfeba6Schristos ctrls = op->o_ctrls;
42392cfeba6Schristos rs->sr_err = asyncmeta_controls_add( op, rs, mc, candidate, be_isroot(op), &ctrls );
42492cfeba6Schristos op->o_dn = save_o_dn;
42592cfeba6Schristos op->o_do_not_cache = save_o_do_not_cache;
42692cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
42792cfeba6Schristos goto return_results;
42892cfeba6Schristos }
42992cfeba6Schristos
43092cfeba6Schristos /* FIXME: this fixes the bind problem right now; we need
43192cfeba6Schristos * to use the asynchronous version to get the "matched"
43292cfeba6Schristos * and more in case of failure ... */
43392cfeba6Schristos /* FIXME: should we check if at least some of the op->o_ctrls
43492cfeba6Schristos * can/should be passed? */
43592cfeba6Schristos for (;;) {
43692cfeba6Schristos rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
43792cfeba6Schristos LDAP_SASL_SIMPLE, &op->orb_cred,
43892cfeba6Schristos ctrls, NULL, &msgid );
43992cfeba6Schristos if ( rs->sr_err != LDAP_X_CONNECTING ) {
44092cfeba6Schristos break;
44192cfeba6Schristos }
44292cfeba6Schristos ldap_pvt_thread_yield();
44392cfeba6Schristos }
44492cfeba6Schristos
44592cfeba6Schristos mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
44692cfeba6Schristos
44792cfeba6Schristos asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, LDAP_BACK_DONTSEND, 1 );
44892cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
44992cfeba6Schristos goto return_results;
45092cfeba6Schristos }
45192cfeba6Schristos
45292cfeba6Schristos /* If defined, proxyAuthz will be used also when
45392cfeba6Schristos * back-ldap is the authorizing backend; for this
45492cfeba6Schristos * purpose, a successful bind is followed by a
45592cfeba6Schristos * bind with the configured identity assertion */
45692cfeba6Schristos /* NOTE: use with care */
45792cfeba6Schristos if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
45892cfeba6Schristos asyncmeta_proxy_authz_bind( mc, candidate, op, rs, LDAP_BACK_SENDERR, 1 );
45992cfeba6Schristos if ( !LDAP_BACK_CONN_ISBOUND( msc ) ) {
46092cfeba6Schristos goto return_results;
46192cfeba6Schristos }
46292cfeba6Schristos goto cache_refresh;
46392cfeba6Schristos }
46492cfeba6Schristos
46592cfeba6Schristos ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_ndn );
46692cfeba6Schristos LDAP_BACK_CONN_ISBOUND_SET( msc );
46792cfeba6Schristos mc->mc_authz_target = candidate;
46892cfeba6Schristos
46992cfeba6Schristos if ( META_BACK_TGT_SAVECRED( mt ) ) {
47092cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_cred ) ) {
47192cfeba6Schristos memset( msc->msc_cred.bv_val, 0,
47292cfeba6Schristos msc->msc_cred.bv_len );
47392cfeba6Schristos }
47492cfeba6Schristos ber_bvreplace( &msc->msc_cred, &op->orb_cred );
47592cfeba6Schristos ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
47692cfeba6Schristos }
47792cfeba6Schristos
47892cfeba6Schristos cache_refresh:;
47992cfeba6Schristos if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
48092cfeba6Schristos && !BER_BVISEMPTY( &op->o_req_ndn ) )
48192cfeba6Schristos {
48292cfeba6Schristos ( void )asyncmeta_dncache_update_entry( &mi->mi_cache,
48392cfeba6Schristos &op->o_req_ndn, candidate );
48492cfeba6Schristos }
48592cfeba6Schristos
48692cfeba6Schristos return_results:;
48792cfeba6Schristos if ( mdn.bv_val != op->o_req_dn.bv_val ) {
48892cfeba6Schristos op->o_tmpfree( mdn.bv_val, op->o_tmpmemctx );
48992cfeba6Schristos }
49092cfeba6Schristos
49192cfeba6Schristos if ( META_BACK_TGT_QUARANTINE( mt ) ) {
49292cfeba6Schristos asyncmeta_quarantine( op, mi, rs, candidate );
49392cfeba6Schristos }
49492cfeba6Schristos ldap_unbind_ext( msc->msc_ld, NULL, NULL );
49592cfeba6Schristos msc->msc_ld = NULL;
49692cfeba6Schristos ldap_ld_free( msc->msc_ldr, 0, NULL, NULL );
49792cfeba6Schristos msc->msc_ldr = NULL;
49892cfeba6Schristos return rs->sr_err;
49992cfeba6Schristos }
50092cfeba6Schristos
50192cfeba6Schristos
50292cfeba6Schristos /*
50392cfeba6Schristos * asyncmeta_back_default_rebind
50492cfeba6Schristos *
50592cfeba6Schristos * This is a callback used for chasing referrals using the same
50692cfeba6Schristos * credentials as the original user on this session.
50792cfeba6Schristos */
50892cfeba6Schristos int
asyncmeta_back_default_rebind(LDAP * ld,LDAP_CONST char * url,ber_tag_t request,ber_int_t msgid,void * params)50992cfeba6Schristos asyncmeta_back_default_rebind(
51092cfeba6Schristos LDAP *ld,
51192cfeba6Schristos LDAP_CONST char *url,
51292cfeba6Schristos ber_tag_t request,
51392cfeba6Schristos ber_int_t msgid,
51492cfeba6Schristos void *params )
51592cfeba6Schristos {
51692cfeba6Schristos a_metasingleconn_t *msc = ( a_metasingleconn_t * )params;
51792cfeba6Schristos
51892cfeba6Schristos return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
51992cfeba6Schristos LDAP_SASL_SIMPLE, &msc->msc_cred,
52092cfeba6Schristos NULL, NULL, NULL );
52192cfeba6Schristos }
52292cfeba6Schristos
52392cfeba6Schristos /*
52492cfeba6Schristos * meta_back_default_urllist
52592cfeba6Schristos *
52692cfeba6Schristos * This is a callback used for mucking with the urllist
52792cfeba6Schristos */
52892cfeba6Schristos int
asyncmeta_back_default_urllist(LDAP * ld,LDAPURLDesc ** urllist,LDAPURLDesc ** url,void * params)52992cfeba6Schristos asyncmeta_back_default_urllist(
53092cfeba6Schristos LDAP *ld,
53192cfeba6Schristos LDAPURLDesc **urllist,
53292cfeba6Schristos LDAPURLDesc **url,
53392cfeba6Schristos void *params )
53492cfeba6Schristos {
53592cfeba6Schristos a_metatarget_t *mt = (a_metatarget_t *)params;
53692cfeba6Schristos LDAPURLDesc **urltail;
53792cfeba6Schristos
53892cfeba6Schristos if ( urllist == url ) {
53992cfeba6Schristos return LDAP_SUCCESS;
54092cfeba6Schristos }
54192cfeba6Schristos
54292cfeba6Schristos for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
54392cfeba6Schristos /* count */ ;
54492cfeba6Schristos
54592cfeba6Schristos *urltail = *urllist;
54692cfeba6Schristos *urllist = *url;
54792cfeba6Schristos *url = NULL;
54892cfeba6Schristos
54992cfeba6Schristos ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
55092cfeba6Schristos if ( mt->mt_uri ) {
55192cfeba6Schristos ch_free( mt->mt_uri );
55292cfeba6Schristos }
55392cfeba6Schristos
55492cfeba6Schristos ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
55592cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
55692cfeba6Schristos
55792cfeba6Schristos return LDAP_SUCCESS;
55892cfeba6Schristos }
55992cfeba6Schristos
56092cfeba6Schristos int
asyncmeta_back_cancel(a_metaconn_t * mc,Operation * op,ber_int_t msgid,int candidate)56192cfeba6Schristos asyncmeta_back_cancel(
56292cfeba6Schristos a_metaconn_t *mc,
56392cfeba6Schristos Operation *op,
56492cfeba6Schristos ber_int_t msgid,
56592cfeba6Schristos int candidate )
56692cfeba6Schristos {
56792cfeba6Schristos
56892cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
56992cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
57092cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
57192cfeba6Schristos
57292cfeba6Schristos int rc = LDAP_OTHER;
57392cfeba6Schristos struct timeval tv = { 0, 0 };
57492cfeba6Schristos ber_socket_t s;
57592cfeba6Schristos
57692cfeba6Schristos Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n",
57792cfeba6Schristos op->o_log_prefix, candidate, msgid );
57892cfeba6Schristos
57992cfeba6Schristos if (!( LDAP_BACK_CONN_ISBOUND( msc )
58092cfeba6Schristos || LDAP_BACK_CONN_ISANON( msc )) || msc->msc_ld == NULL ) {
58192cfeba6Schristos Debug( LDAP_DEBUG_TRACE, ">>> %s asyncmeta_back_cancel[%d] msgid=%d\n already reset",
58292cfeba6Schristos op->o_log_prefix, candidate, msgid );
58392cfeba6Schristos return LDAP_SUCCESS;
58492cfeba6Schristos }
58592cfeba6Schristos
58692cfeba6Schristos ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
58792cfeba6Schristos if (s < 0) {
58892cfeba6Schristos return rc;
58992cfeba6Schristos }
59092cfeba6Schristos rc = ldap_int_poll( msc->msc_ld, s, &tv, 1);
59192cfeba6Schristos if (rc < 0) {
59292cfeba6Schristos rc = LDAP_SERVER_DOWN;
59392cfeba6Schristos return rc;
59492cfeba6Schristos }
59592cfeba6Schristos /* default behavior */
59692cfeba6Schristos if ( META_BACK_TGT_ABANDON( mt ) ) {
59792cfeba6Schristos rc = ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
59892cfeba6Schristos
59992cfeba6Schristos } else if ( META_BACK_TGT_IGNORE( mt ) ) {
60092cfeba6Schristos rc = ldap_pvt_discard( msc->msc_ld, msgid );
60192cfeba6Schristos
60292cfeba6Schristos } else if ( META_BACK_TGT_CANCEL( mt ) ) {
60392cfeba6Schristos rc = ldap_cancel_s( msc->msc_ld, msgid, NULL, NULL );
60492cfeba6Schristos
60592cfeba6Schristos } else {
60692cfeba6Schristos assert( 0 );
60792cfeba6Schristos }
60892cfeba6Schristos
60992cfeba6Schristos Debug( LDAP_DEBUG_TRACE, "<<< %s asyncmeta_back_cancel[%d] err=%d\n",
61092cfeba6Schristos op->o_log_prefix, candidate, rc );
61192cfeba6Schristos
61292cfeba6Schristos return rc;
61392cfeba6Schristos }
61492cfeba6Schristos
61592cfeba6Schristos
61692cfeba6Schristos
61792cfeba6Schristos /*
61892cfeba6Schristos * asyncmeta_back_proxy_authz_cred()
61992cfeba6Schristos *
62092cfeba6Schristos * prepares credentials & method for meta_back_proxy_authz_bind();
62192cfeba6Schristos * or, if method is SASL, performs the SASL bind directly.
62292cfeba6Schristos */
62392cfeba6Schristos int
asyncmeta_back_proxy_authz_cred(a_metaconn_t * mc,int candidate,Operation * op,SlapReply * rs,ldap_back_send_t sendok,struct berval * binddn,struct berval * bindcred,int * method)62492cfeba6Schristos asyncmeta_back_proxy_authz_cred(
62592cfeba6Schristos a_metaconn_t *mc,
62692cfeba6Schristos int candidate,
62792cfeba6Schristos Operation *op,
62892cfeba6Schristos SlapReply *rs,
62992cfeba6Schristos ldap_back_send_t sendok,
63092cfeba6Schristos struct berval *binddn,
63192cfeba6Schristos struct berval *bindcred,
63292cfeba6Schristos int *method )
63392cfeba6Schristos {
63492cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
63592cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
63692cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
63792cfeba6Schristos struct berval ndn;
63892cfeba6Schristos int dobind = 0;
63992cfeba6Schristos struct timeval old_tv = {0, 0};
64092cfeba6Schristos struct timeval bind_tv = { mt->mt_timeout[ SLAP_OP_BIND ], 0};
64192cfeba6Schristos /* don't proxyAuthz if protocol is not LDAPv3 */
64292cfeba6Schristos switch ( mt->mt_version ) {
64392cfeba6Schristos case LDAP_VERSION3:
64492cfeba6Schristos break;
64592cfeba6Schristos
64692cfeba6Schristos case 0:
64792cfeba6Schristos if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
64892cfeba6Schristos break;
64992cfeba6Schristos }
65092cfeba6Schristos /* fall thru */
65192cfeba6Schristos
65292cfeba6Schristos default:
65392cfeba6Schristos rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
65492cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
65592cfeba6Schristos send_ldap_result( op, rs );
65692cfeba6Schristos }
65792cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
65892cfeba6Schristos goto done;
65992cfeba6Schristos }
66092cfeba6Schristos
66192cfeba6Schristos if ( op->o_tag == LDAP_REQ_BIND ) {
66292cfeba6Schristos ndn = op->o_req_ndn;
66392cfeba6Schristos
66492cfeba6Schristos } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
66592cfeba6Schristos ndn = op->o_conn->c_ndn;
66692cfeba6Schristos
66792cfeba6Schristos } else {
66892cfeba6Schristos ndn = op->o_ndn;
66992cfeba6Schristos }
67092cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
67192cfeba6Schristos
67292cfeba6Schristos /*
67392cfeba6Schristos * FIXME: we need to let clients use proxyAuthz
67492cfeba6Schristos * otherwise we cannot do symmetric pools of servers;
67592cfeba6Schristos * we have to live with the fact that a user can
67692cfeba6Schristos * authorize itself as any ID that is allowed
67792cfeba6Schristos * by the authzTo directive of the "proxyauthzdn".
67892cfeba6Schristos */
67992cfeba6Schristos /*
68092cfeba6Schristos * NOTE: current Proxy Authorization specification
68192cfeba6Schristos * and implementation do not allow proxy authorization
68292cfeba6Schristos * control to be provided with Bind requests
68392cfeba6Schristos */
68492cfeba6Schristos /*
68592cfeba6Schristos * if no bind took place yet, but the connection is bound
68692cfeba6Schristos * and the "proxyauthzdn" is set, then bind as
68792cfeba6Schristos * "proxyauthzdn" and explicitly add the proxyAuthz
68892cfeba6Schristos * control to every operation with the dn bound
68992cfeba6Schristos * to the connection as control value.
69092cfeba6Schristos */
69192cfeba6Schristos
69292cfeba6Schristos /* bind as proxyauthzdn only if no idassert mode
69392cfeba6Schristos * is requested, or if the client's identity
69492cfeba6Schristos * is authorized */
69592cfeba6Schristos switch ( mt->mt_idassert_mode ) {
69692cfeba6Schristos case LDAP_BACK_IDASSERT_LEGACY:
69792cfeba6Schristos if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
69892cfeba6Schristos if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) && !BER_BVISEMPTY( &mt->mt_idassert_authcDN ) )
69992cfeba6Schristos {
70092cfeba6Schristos *binddn = mt->mt_idassert_authcDN;
70192cfeba6Schristos *bindcred = mt->mt_idassert_passwd;
70292cfeba6Schristos dobind = 1;
70392cfeba6Schristos }
70492cfeba6Schristos }
70592cfeba6Schristos break;
70692cfeba6Schristos
70792cfeba6Schristos default:
70892cfeba6Schristos /* NOTE: rootdn can always idassert */
70992cfeba6Schristos if ( BER_BVISNULL( &ndn )
71092cfeba6Schristos && mt->mt_idassert_authz == NULL
71192cfeba6Schristos && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
71292cfeba6Schristos {
71392cfeba6Schristos if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
71492cfeba6Schristos rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
71592cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
71692cfeba6Schristos send_ldap_result( op, rs );
71792cfeba6Schristos }
71892cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
71992cfeba6Schristos goto done;
72092cfeba6Schristos
72192cfeba6Schristos }
72292cfeba6Schristos
72392cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
72492cfeba6Schristos *binddn = slap_empty_bv;
72592cfeba6Schristos *bindcred = slap_empty_bv;
72692cfeba6Schristos break;
72792cfeba6Schristos
72892cfeba6Schristos } else if ( mt->mt_idassert_authz && !be_isroot( op ) ) {
72992cfeba6Schristos struct berval authcDN;
73092cfeba6Schristos
73192cfeba6Schristos if ( BER_BVISNULL( &ndn ) ) {
73292cfeba6Schristos authcDN = slap_empty_bv;
73392cfeba6Schristos
73492cfeba6Schristos } else {
73592cfeba6Schristos authcDN = ndn;
73692cfeba6Schristos }
73792cfeba6Schristos rs->sr_err = slap_sasl_matches( op, mt->mt_idassert_authz,
73892cfeba6Schristos &authcDN, &authcDN );
73992cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
74092cfeba6Schristos if ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
74192cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
74292cfeba6Schristos send_ldap_result( op, rs );
74392cfeba6Schristos }
74492cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
74592cfeba6Schristos goto done;
74692cfeba6Schristos }
74792cfeba6Schristos
74892cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
74992cfeba6Schristos *binddn = slap_empty_bv;
75092cfeba6Schristos *bindcred = slap_empty_bv;
75192cfeba6Schristos break;
75292cfeba6Schristos }
75392cfeba6Schristos }
75492cfeba6Schristos
75592cfeba6Schristos *binddn = mt->mt_idassert_authcDN;
75692cfeba6Schristos *bindcred = mt->mt_idassert_passwd;
75792cfeba6Schristos dobind = 1;
75892cfeba6Schristos break;
75992cfeba6Schristos }
76092cfeba6Schristos
76192cfeba6Schristos if ( dobind && mt->mt_idassert_authmethod == LDAP_AUTH_SASL ) {
76292cfeba6Schristos #ifdef HAVE_CYRUS_SASL
76392cfeba6Schristos void *defaults = NULL;
76492cfeba6Schristos struct berval authzID = BER_BVNULL;
76592cfeba6Schristos int freeauthz = 0;
76692cfeba6Schristos
76792cfeba6Schristos /* if SASL supports native authz, prepare for it */
76892cfeba6Schristos if ( ( !op->o_do_not_cache || !op->o_is_auth_check ) &&
76992cfeba6Schristos ( mt->mt_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
77092cfeba6Schristos {
77192cfeba6Schristos switch ( mt->mt_idassert_mode ) {
77292cfeba6Schristos case LDAP_BACK_IDASSERT_OTHERID:
77392cfeba6Schristos case LDAP_BACK_IDASSERT_OTHERDN:
77492cfeba6Schristos authzID = mt->mt_idassert_authzID;
77592cfeba6Schristos break;
77692cfeba6Schristos
77792cfeba6Schristos case LDAP_BACK_IDASSERT_ANONYMOUS:
77892cfeba6Schristos BER_BVSTR( &authzID, "dn:" );
77992cfeba6Schristos break;
78092cfeba6Schristos
78192cfeba6Schristos case LDAP_BACK_IDASSERT_SELF:
78292cfeba6Schristos if ( BER_BVISNULL( &ndn ) ) {
78392cfeba6Schristos /* connection is not authc'd, so don't idassert */
78492cfeba6Schristos BER_BVSTR( &authzID, "dn:" );
78592cfeba6Schristos break;
78692cfeba6Schristos }
78792cfeba6Schristos authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
78892cfeba6Schristos authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
78992cfeba6Schristos AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
79092cfeba6Schristos AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
79192cfeba6Schristos ndn.bv_val, ndn.bv_len + 1 );
79292cfeba6Schristos freeauthz = 1;
79392cfeba6Schristos break;
79492cfeba6Schristos
79592cfeba6Schristos default:
79692cfeba6Schristos break;
79792cfeba6Schristos }
79892cfeba6Schristos }
79992cfeba6Schristos
80092cfeba6Schristos if ( mt->mt_idassert_secprops != NULL ) {
80192cfeba6Schristos rs->sr_err = ldap_set_option( msc->msc_ld,
80292cfeba6Schristos LDAP_OPT_X_SASL_SECPROPS,
80392cfeba6Schristos (void *)mt->mt_idassert_secprops );
80492cfeba6Schristos
80592cfeba6Schristos if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
80692cfeba6Schristos rs->sr_err = LDAP_OTHER;
80792cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
80892cfeba6Schristos send_ldap_result( op, rs );
80992cfeba6Schristos }
81092cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
81192cfeba6Schristos goto done;
81292cfeba6Schristos }
81392cfeba6Schristos }
81492cfeba6Schristos
81592cfeba6Schristos ldap_get_option( msc->msc_ld, LDAP_OPT_TIMEOUT, (void *)&old_tv);
81692cfeba6Schristos
81792cfeba6Schristos if (mt->mt_timeout[ SLAP_OP_BIND ] > 0 ) {
81892cfeba6Schristos rs->sr_err = ldap_set_option( msc->msc_ld,
81992cfeba6Schristos LDAP_OPT_TIMEOUT,
82092cfeba6Schristos (void *)&bind_tv );
82192cfeba6Schristos
82292cfeba6Schristos if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
82392cfeba6Schristos rs->sr_err = LDAP_OTHER;
82492cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
82592cfeba6Schristos send_ldap_result( op, rs );
82692cfeba6Schristos }
82792cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
82892cfeba6Schristos goto done;
82992cfeba6Schristos }
83092cfeba6Schristos }
83192cfeba6Schristos defaults = lutil_sasl_defaults( msc->msc_ld,
83292cfeba6Schristos mt->mt_idassert_sasl_mech.bv_val,
83392cfeba6Schristos mt->mt_idassert_sasl_realm.bv_val,
83492cfeba6Schristos mt->mt_idassert_authcID.bv_val,
83592cfeba6Schristos mt->mt_idassert_passwd.bv_val,
83692cfeba6Schristos authzID.bv_val );
83792cfeba6Schristos if ( defaults == NULL ) {
83892cfeba6Schristos rs->sr_err = LDAP_OTHER;
83992cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
84092cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
84192cfeba6Schristos send_ldap_result( op, rs );
84292cfeba6Schristos }
84392cfeba6Schristos goto done;
84492cfeba6Schristos }
84592cfeba6Schristos
84692cfeba6Schristos rs->sr_err = ldap_sasl_interactive_bind_s( msc->msc_ld, binddn->bv_val,
84792cfeba6Schristos mt->mt_idassert_sasl_mech.bv_val, NULL, NULL,
84892cfeba6Schristos LDAP_SASL_QUIET, lutil_sasl_interact,
84992cfeba6Schristos defaults );
85092cfeba6Schristos
85192cfeba6Schristos /* restore the old timeout just in case */
85292cfeba6Schristos ldap_set_option( msc->msc_ld, LDAP_OPT_TIMEOUT, (void *)&old_tv );
85392cfeba6Schristos
85492cfeba6Schristos rs->sr_err = slap_map_api2result( rs );
85592cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
85692cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
85792cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
85892cfeba6Schristos asyncmeta_get_timestamp(time_buf);
85992cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_back_proxy_authz_cred failed bind msc: %p\n",
86092cfeba6Schristos time_buf, msc );
86192cfeba6Schristos }
86292cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
86392cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
86492cfeba6Schristos send_ldap_result( op, rs );
86592cfeba6Schristos }
86692cfeba6Schristos
86792cfeba6Schristos } else {
86892cfeba6Schristos LDAP_BACK_CONN_ISBOUND_SET( msc );
86992cfeba6Schristos }
87092cfeba6Schristos
87192cfeba6Schristos lutil_sasl_freedefs( defaults );
87292cfeba6Schristos if ( freeauthz ) {
87392cfeba6Schristos slap_sl_free( authzID.bv_val, op->o_tmpmemctx );
87492cfeba6Schristos }
87592cfeba6Schristos
87692cfeba6Schristos goto done;
87792cfeba6Schristos #endif /* HAVE_CYRUS_SASL */
87892cfeba6Schristos }
87992cfeba6Schristos
88092cfeba6Schristos *method = mt->mt_idassert_authmethod;
88192cfeba6Schristos switch ( mt->mt_idassert_authmethod ) {
88292cfeba6Schristos case LDAP_AUTH_NONE:
88392cfeba6Schristos BER_BVSTR( binddn, "" );
88492cfeba6Schristos BER_BVSTR( bindcred, "" );
88592cfeba6Schristos /* fallthru */
88692cfeba6Schristos
88792cfeba6Schristos case LDAP_AUTH_SIMPLE:
88892cfeba6Schristos break;
88992cfeba6Schristos
89092cfeba6Schristos default:
89192cfeba6Schristos /* unsupported! */
89292cfeba6Schristos LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
89392cfeba6Schristos rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
89492cfeba6Schristos if ( sendok & LDAP_BACK_SENDERR ) {
89592cfeba6Schristos send_ldap_result( op, rs );
89692cfeba6Schristos }
89792cfeba6Schristos break;
89892cfeba6Schristos }
89992cfeba6Schristos
90092cfeba6Schristos done:;
90192cfeba6Schristos
90292cfeba6Schristos if ( !BER_BVISEMPTY( binddn ) ) {
90392cfeba6Schristos LDAP_BACK_CONN_ISIDASSERT_SET( msc );
90492cfeba6Schristos }
90592cfeba6Schristos
90692cfeba6Schristos return rs->sr_err;
90792cfeba6Schristos }
90892cfeba6Schristos
90992cfeba6Schristos static int
asyncmeta_proxy_authz_bind(a_metaconn_t * mc,int candidate,Operation * op,SlapReply * rs,ldap_back_send_t sendok,int dolock)91092cfeba6Schristos asyncmeta_proxy_authz_bind(
91192cfeba6Schristos a_metaconn_t *mc,
91292cfeba6Schristos int candidate,
91392cfeba6Schristos Operation *op,
91492cfeba6Schristos SlapReply *rs,
91592cfeba6Schristos ldap_back_send_t sendok,
91692cfeba6Schristos int dolock )
91792cfeba6Schristos {
91892cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
91992cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
92092cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
92192cfeba6Schristos struct berval binddn = BER_BVC( "" ),
92292cfeba6Schristos cred = BER_BVC( "" );
92392cfeba6Schristos int method = LDAP_AUTH_NONE,
92492cfeba6Schristos rc;
92592cfeba6Schristos
92692cfeba6Schristos rc = asyncmeta_back_proxy_authz_cred( mc, candidate, op, rs, sendok, &binddn, &cred, &method );
92792cfeba6Schristos if ( rc == LDAP_SUCCESS && !LDAP_BACK_CONN_ISBOUND( msc ) ) {
92892cfeba6Schristos int msgid;
92992cfeba6Schristos
93092cfeba6Schristos switch ( method ) {
93192cfeba6Schristos case LDAP_AUTH_NONE:
93292cfeba6Schristos case LDAP_AUTH_SIMPLE:
93392cfeba6Schristos for (;;) {
93492cfeba6Schristos rs->sr_err = ldap_sasl_bind( msc->msc_ld,
93592cfeba6Schristos binddn.bv_val, LDAP_SASL_SIMPLE,
93692cfeba6Schristos &cred, NULL, NULL, &msgid );
93792cfeba6Schristos if ( rs->sr_err != LDAP_X_CONNECTING ) {
93892cfeba6Schristos break;
93992cfeba6Schristos }
94092cfeba6Schristos ldap_pvt_thread_yield();
94192cfeba6Schristos }
94292cfeba6Schristos
94392cfeba6Schristos rc = asyncmeta_bind_op_result( op, rs, mc, candidate, msgid, sendok, dolock );
94492cfeba6Schristos if ( rc == LDAP_SUCCESS ) {
94592cfeba6Schristos /* set rebind stuff in case of successful proxyAuthz bind,
94692cfeba6Schristos * so that referral chasing is attempted using the right
94792cfeba6Schristos * identity */
94892cfeba6Schristos LDAP_BACK_CONN_ISBOUND_SET( msc );
94992cfeba6Schristos ber_bvreplace( &msc->msc_bound_ndn, &binddn );
95092cfeba6Schristos
95192cfeba6Schristos if ( META_BACK_TGT_SAVECRED( mt ) ) {
95292cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_cred ) ) {
95392cfeba6Schristos memset( msc->msc_cred.bv_val, 0,
95492cfeba6Schristos msc->msc_cred.bv_len );
95592cfeba6Schristos }
95692cfeba6Schristos ber_bvreplace( &msc->msc_cred, &cred );
95792cfeba6Schristos ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
95892cfeba6Schristos }
95992cfeba6Schristos }
96092cfeba6Schristos break;
96192cfeba6Schristos
96292cfeba6Schristos default:
96392cfeba6Schristos assert( 0 );
96492cfeba6Schristos break;
96592cfeba6Schristos }
96692cfeba6Schristos }
96792cfeba6Schristos
96892cfeba6Schristos return LDAP_BACK_CONN_ISBOUND( msc );
96992cfeba6Schristos }
97092cfeba6Schristos
97192cfeba6Schristos
97292cfeba6Schristos static int
asyncmeta_back_proxy_authz_ctrl(Operation * op,SlapReply * rs,struct berval * bound_ndn,int version,int isroot,slap_idassert_t * si,LDAPControl * ctrl)97392cfeba6Schristos asyncmeta_back_proxy_authz_ctrl(Operation *op,
97492cfeba6Schristos SlapReply *rs,
97592cfeba6Schristos struct berval *bound_ndn,
97692cfeba6Schristos int version,
97792cfeba6Schristos int isroot,
97892cfeba6Schristos slap_idassert_t *si,
97992cfeba6Schristos LDAPControl *ctrl )
98092cfeba6Schristos {
98192cfeba6Schristos slap_idassert_mode_t mode;
98292cfeba6Schristos struct berval assertedID,
98392cfeba6Schristos ndn;
98492cfeba6Schristos
98592cfeba6Schristos rs->sr_err = SLAP_CB_CONTINUE;
98692cfeba6Schristos
98792cfeba6Schristos /* FIXME: SASL/EXTERNAL over ldapi:// doesn't honor the authcID,
98892cfeba6Schristos * but if it is not set this test fails. We need a different
98992cfeba6Schristos * means to detect if idassert is enabled */
99092cfeba6Schristos if ( ( BER_BVISNULL( &si->si_bc.sb_authcId ) || BER_BVISEMPTY( &si->si_bc.sb_authcId ) )
99192cfeba6Schristos && ( BER_BVISNULL( &si->si_bc.sb_binddn ) || BER_BVISEMPTY( &si->si_bc.sb_binddn ) )
99292cfeba6Schristos && BER_BVISNULL( &si->si_bc.sb_saslmech ) )
99392cfeba6Schristos {
99492cfeba6Schristos goto done;
99592cfeba6Schristos }
99692cfeba6Schristos
99792cfeba6Schristos if ( !op->o_conn || op->o_do_not_cache || ( isroot ) ) {
99892cfeba6Schristos goto done;
99992cfeba6Schristos }
100092cfeba6Schristos
100192cfeba6Schristos if ( op->o_tag == LDAP_REQ_BIND ) {
100292cfeba6Schristos ndn = op->o_req_ndn;
100392cfeba6Schristos
100492cfeba6Schristos #if 0
100592cfeba6Schristos } else if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
100692cfeba6Schristos ndn = op->o_conn->c_ndn;
100792cfeba6Schristos #endif
100892cfeba6Schristos } else {
100992cfeba6Schristos ndn = op->o_ndn;
101092cfeba6Schristos }
101192cfeba6Schristos
101292cfeba6Schristos if ( si->si_mode == LDAP_BACK_IDASSERT_LEGACY ) {
101392cfeba6Schristos if ( op->o_proxy_authz ) {
101492cfeba6Schristos /*
101592cfeba6Schristos * FIXME: we do not want to perform proxyAuthz
101692cfeba6Schristos * on behalf of the client, because this would
101792cfeba6Schristos * be performed with "proxyauthzdn" privileges.
101892cfeba6Schristos *
101992cfeba6Schristos * This might actually be too strict, since
102092cfeba6Schristos * the "proxyauthzdn" authzTo, and each entry's
102192cfeba6Schristos * authzFrom attributes may be crafted
102292cfeba6Schristos * to avoid unwanted proxyAuthz to take place.
102392cfeba6Schristos */
102492cfeba6Schristos #if 0
102592cfeba6Schristos rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
102692cfeba6Schristos rs->sr_text = "proxyAuthz not allowed within namingContext";
102792cfeba6Schristos #endif
102892cfeba6Schristos goto done;
102992cfeba6Schristos }
103092cfeba6Schristos
103192cfeba6Schristos if ( !BER_BVISNULL( bound_ndn ) ) {
103292cfeba6Schristos goto done;
103392cfeba6Schristos }
103492cfeba6Schristos
103592cfeba6Schristos if ( BER_BVISNULL( &ndn ) ) {
103692cfeba6Schristos goto done;
103792cfeba6Schristos }
103892cfeba6Schristos
103992cfeba6Schristos if ( BER_BVISNULL( &si->si_bc.sb_binddn ) ) {
104092cfeba6Schristos goto done;
104192cfeba6Schristos }
104292cfeba6Schristos
104392cfeba6Schristos } else if ( si->si_bc.sb_method == LDAP_AUTH_SASL ) {
104492cfeba6Schristos if ( ( si->si_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ ) )
104592cfeba6Schristos {
104692cfeba6Schristos /* already asserted in SASL via native authz */
104792cfeba6Schristos goto done;
104892cfeba6Schristos }
104992cfeba6Schristos
105092cfeba6Schristos } else if ( si->si_authz && !isroot ) {
105192cfeba6Schristos int rc;
105292cfeba6Schristos struct berval authcDN;
105392cfeba6Schristos
105492cfeba6Schristos if ( BER_BVISNULL( &ndn ) ) {
105592cfeba6Schristos authcDN = slap_empty_bv;
105692cfeba6Schristos } else {
105792cfeba6Schristos authcDN = ndn;
105892cfeba6Schristos }
105992cfeba6Schristos rc = slap_sasl_matches( op, si->si_authz,
106092cfeba6Schristos &authcDN, &authcDN );
106192cfeba6Schristos if ( rc != LDAP_SUCCESS ) {
106292cfeba6Schristos if ( si->si_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
106392cfeba6Schristos /* ndn is not authorized
106492cfeba6Schristos * to use idassert */
106592cfeba6Schristos rs->sr_err = rc;
106692cfeba6Schristos }
106792cfeba6Schristos goto done;
106892cfeba6Schristos }
106992cfeba6Schristos }
107092cfeba6Schristos
107192cfeba6Schristos if ( op->o_proxy_authz ) {
107292cfeba6Schristos /*
107392cfeba6Schristos * FIXME: we can:
107492cfeba6Schristos * 1) ignore the already set proxyAuthz control
107592cfeba6Schristos * 2) leave it in place, and don't set ours
107692cfeba6Schristos * 3) add both
107792cfeba6Schristos * 4) reject the operation
107892cfeba6Schristos *
107992cfeba6Schristos * option (4) is very drastic
108092cfeba6Schristos * option (3) will make the remote server reject
108192cfeba6Schristos * the operation, thus being equivalent to (4)
108292cfeba6Schristos * option (2) will likely break the idassert
108392cfeba6Schristos * assumptions, so we cannot accept it;
108492cfeba6Schristos * option (1) means that we are contradicting
108592cfeba6Schristos * the client's request.
108692cfeba6Schristos *
108792cfeba6Schristos * I think (4) is the only correct choice.
108892cfeba6Schristos */
108992cfeba6Schristos rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
109092cfeba6Schristos rs->sr_text = "proxyAuthz not allowed within namingContext";
109192cfeba6Schristos }
109292cfeba6Schristos
109392cfeba6Schristos if ( op->o_is_auth_check ) {
109492cfeba6Schristos mode = LDAP_BACK_IDASSERT_NOASSERT;
109592cfeba6Schristos
109692cfeba6Schristos } else {
109792cfeba6Schristos mode = si->si_mode;
109892cfeba6Schristos }
109992cfeba6Schristos
110092cfeba6Schristos switch ( mode ) {
110192cfeba6Schristos case LDAP_BACK_IDASSERT_LEGACY:
110292cfeba6Schristos /* original behavior:
110392cfeba6Schristos * assert the client's identity */
110492cfeba6Schristos case LDAP_BACK_IDASSERT_SELF:
110592cfeba6Schristos assertedID = ndn;
110692cfeba6Schristos break;
110792cfeba6Schristos
110892cfeba6Schristos case LDAP_BACK_IDASSERT_ANONYMOUS:
110992cfeba6Schristos /* assert "anonymous" */
111092cfeba6Schristos assertedID = slap_empty_bv;
111192cfeba6Schristos break;
111292cfeba6Schristos
111392cfeba6Schristos case LDAP_BACK_IDASSERT_NOASSERT:
111492cfeba6Schristos /* don't assert; bind as proxyauthzdn */
111592cfeba6Schristos goto done;
111692cfeba6Schristos
111792cfeba6Schristos case LDAP_BACK_IDASSERT_OTHERID:
111892cfeba6Schristos case LDAP_BACK_IDASSERT_OTHERDN:
111992cfeba6Schristos /* assert idassert DN */
112092cfeba6Schristos assertedID = si->si_bc.sb_authzId;
112192cfeba6Schristos break;
112292cfeba6Schristos
112392cfeba6Schristos default:
112492cfeba6Schristos assert( 0 );
112592cfeba6Schristos }
112692cfeba6Schristos
112792cfeba6Schristos /* if we got here, "" is allowed to proxyAuthz */
112892cfeba6Schristos if ( BER_BVISNULL( &assertedID ) ) {
112992cfeba6Schristos assertedID = slap_empty_bv;
113092cfeba6Schristos }
113192cfeba6Schristos
113292cfeba6Schristos /* don't idassert the bound DN (ITS#4497) */
113392cfeba6Schristos if ( dn_match( &assertedID, bound_ndn ) ) {
113492cfeba6Schristos goto done;
113592cfeba6Schristos }
113692cfeba6Schristos
113792cfeba6Schristos ctrl->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
113892cfeba6Schristos ctrl->ldctl_iscritical = ( ( si->si_flags & LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL ) == LDAP_BACK_AUTH_PROXYAUTHZ_CRITICAL );
113992cfeba6Schristos
114092cfeba6Schristos switch ( si->si_mode ) {
114192cfeba6Schristos /* already in u:ID or dn:DN form */
114292cfeba6Schristos case LDAP_BACK_IDASSERT_OTHERID:
114392cfeba6Schristos case LDAP_BACK_IDASSERT_OTHERDN:
114492cfeba6Schristos ber_dupbv_x( &ctrl->ldctl_value, &assertedID, op->o_tmpmemctx );
114592cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
114692cfeba6Schristos break;
114792cfeba6Schristos
114892cfeba6Schristos /* needs the dn: prefix */
114992cfeba6Schristos default:
115092cfeba6Schristos ctrl->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
115192cfeba6Schristos ctrl->ldctl_value.bv_val = op->o_tmpalloc( ctrl->ldctl_value.bv_len + 1,
115292cfeba6Schristos op->o_tmpmemctx );
115392cfeba6Schristos AC_MEMCPY( ctrl->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
115492cfeba6Schristos AC_MEMCPY( &ctrl->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
115592cfeba6Schristos assertedID.bv_val, assertedID.bv_len + 1 );
115692cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
115792cfeba6Schristos break;
115892cfeba6Schristos }
115992cfeba6Schristos
116092cfeba6Schristos /* Older versions of <draft-weltman-ldapv3-proxy> required
116192cfeba6Schristos * to encode the value of the authzID (and called it proxyDN);
116292cfeba6Schristos * this hack provides compatibility with those DSAs that
116392cfeba6Schristos * implement it this way */
116492cfeba6Schristos if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_ENCODING_WORKAROUND ) {
116592cfeba6Schristos struct berval authzID = ctrl->ldctl_value;
116692cfeba6Schristos BerElementBuffer berbuf;
116792cfeba6Schristos BerElement *ber = (BerElement *)&berbuf;
116892cfeba6Schristos ber_tag_t tag;
116992cfeba6Schristos
117092cfeba6Schristos ber_init2( ber, 0, LBER_USE_DER );
117192cfeba6Schristos ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
117292cfeba6Schristos
117392cfeba6Schristos tag = ber_printf( ber, "O", &authzID );
117492cfeba6Schristos if ( tag == LBER_ERROR ) {
117592cfeba6Schristos rs->sr_err = LDAP_OTHER;
117692cfeba6Schristos goto free_ber;
117792cfeba6Schristos }
117892cfeba6Schristos
117992cfeba6Schristos if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
118092cfeba6Schristos rs->sr_err = LDAP_OTHER;
118192cfeba6Schristos goto free_ber;
118292cfeba6Schristos }
118392cfeba6Schristos
118492cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
118592cfeba6Schristos
118692cfeba6Schristos free_ber:;
118792cfeba6Schristos op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
118892cfeba6Schristos ber_free_buf( ber );
118992cfeba6Schristos
119092cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
119192cfeba6Schristos goto done;
119292cfeba6Schristos }
119392cfeba6Schristos
119492cfeba6Schristos } else if ( si->si_flags & LDAP_BACK_AUTH_OBSOLETE_PROXY_AUTHZ ) {
119592cfeba6Schristos struct berval authzID = ctrl->ldctl_value,
119692cfeba6Schristos tmp;
119792cfeba6Schristos BerElementBuffer berbuf;
119892cfeba6Schristos BerElement *ber = (BerElement *)&berbuf;
119992cfeba6Schristos ber_tag_t tag;
120092cfeba6Schristos
120192cfeba6Schristos if ( strncasecmp( authzID.bv_val, "dn:", STRLENOF( "dn:" ) ) != 0 ) {
120292cfeba6Schristos rs->sr_err = LDAP_PROTOCOL_ERROR;
120392cfeba6Schristos goto done;
120492cfeba6Schristos }
120592cfeba6Schristos
120692cfeba6Schristos tmp = authzID;
120792cfeba6Schristos tmp.bv_val += STRLENOF( "dn:" );
120892cfeba6Schristos tmp.bv_len -= STRLENOF( "dn:" );
120992cfeba6Schristos
121092cfeba6Schristos ber_init2( ber, 0, LBER_USE_DER );
121192cfeba6Schristos ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
121292cfeba6Schristos
121392cfeba6Schristos /* apparently, Mozilla API encodes this
121492cfeba6Schristos * as "SEQUENCE { LDAPDN }" */
121592cfeba6Schristos tag = ber_printf( ber, "{O}", &tmp );
121692cfeba6Schristos if ( tag == LBER_ERROR ) {
121792cfeba6Schristos rs->sr_err = LDAP_OTHER;
121892cfeba6Schristos goto free_ber2;
121992cfeba6Schristos }
122092cfeba6Schristos
122192cfeba6Schristos if ( ber_flatten2( ber, &ctrl->ldctl_value, 1 ) == -1 ) {
122292cfeba6Schristos rs->sr_err = LDAP_OTHER;
122392cfeba6Schristos goto free_ber2;
122492cfeba6Schristos }
122592cfeba6Schristos
122692cfeba6Schristos ctrl->ldctl_oid = LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ;
122792cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
122892cfeba6Schristos
122992cfeba6Schristos free_ber2:;
123092cfeba6Schristos op->o_tmpfree( authzID.bv_val, op->o_tmpmemctx );
123192cfeba6Schristos ber_free_buf( ber );
123292cfeba6Schristos
123392cfeba6Schristos if ( rs->sr_err != LDAP_SUCCESS ) {
123492cfeba6Schristos goto done;
123592cfeba6Schristos }
123692cfeba6Schristos }
123792cfeba6Schristos
123892cfeba6Schristos done:;
123992cfeba6Schristos
124092cfeba6Schristos return rs->sr_err;
124192cfeba6Schristos }
124292cfeba6Schristos
124392cfeba6Schristos /*
124492cfeba6Schristos * Add controls;
124592cfeba6Schristos *
124692cfeba6Schristos * if any needs to be added, it is prepended to existing ones,
124792cfeba6Schristos * in a newly allocated array. The companion function
124892cfeba6Schristos * mi->mi_ldap_extra->controls_free() must be used to restore the original
124992cfeba6Schristos * status of op->o_ctrls.
125092cfeba6Schristos */
125192cfeba6Schristos int
asyncmeta_controls_add(Operation * op,SlapReply * rs,a_metaconn_t * mc,int candidate,int isroot,LDAPControl *** pctrls)125292cfeba6Schristos asyncmeta_controls_add( Operation *op,
125392cfeba6Schristos SlapReply *rs,
125492cfeba6Schristos a_metaconn_t *mc,
125592cfeba6Schristos int candidate,
125692cfeba6Schristos int isroot,
125792cfeba6Schristos LDAPControl ***pctrls )
125892cfeba6Schristos {
125992cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
126092cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
126192cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
126292cfeba6Schristos
126392cfeba6Schristos LDAPControl **ctrls = NULL;
126492cfeba6Schristos /* set to the maximum number of controls this backend can add */
126592cfeba6Schristos LDAPControl c[ 2 ] = {{ 0 }};
126692cfeba6Schristos int n = 0, i, j1 = 0, j2 = 0, skipped = 0;
126792cfeba6Schristos
126892cfeba6Schristos *pctrls = NULL;
126992cfeba6Schristos
127092cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
127192cfeba6Schristos
127292cfeba6Schristos /* don't add controls if protocol is not LDAPv3 */
127392cfeba6Schristos switch ( mt->mt_version ) {
127492cfeba6Schristos case LDAP_VERSION3:
127592cfeba6Schristos break;
127692cfeba6Schristos
127792cfeba6Schristos case 0:
127892cfeba6Schristos if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
127992cfeba6Schristos break;
128092cfeba6Schristos }
128192cfeba6Schristos /* fall thru */
128292cfeba6Schristos
128392cfeba6Schristos default:
128492cfeba6Schristos goto done;
128592cfeba6Schristos }
128692cfeba6Schristos
128792cfeba6Schristos /* put controls that go __before__ existing ones here */
128892cfeba6Schristos
128992cfeba6Schristos /* proxyAuthz for identity assertion */
129092cfeba6Schristos switch ( asyncmeta_back_proxy_authz_ctrl( op, rs, &msc->msc_bound_ndn,
129192cfeba6Schristos mt->mt_version, isroot, &mt->mt_idassert, &c[ j1 ] ) )
129292cfeba6Schristos {
129392cfeba6Schristos case SLAP_CB_CONTINUE:
129492cfeba6Schristos break;
129592cfeba6Schristos
129692cfeba6Schristos case LDAP_SUCCESS:
129792cfeba6Schristos j1++;
129892cfeba6Schristos break;
129992cfeba6Schristos
130092cfeba6Schristos default:
130192cfeba6Schristos goto done;
130292cfeba6Schristos }
130392cfeba6Schristos
130492cfeba6Schristos /* put controls that go __after__ existing ones here */
130592cfeba6Schristos
130692cfeba6Schristos #ifdef SLAP_CONTROL_X_SESSION_TRACKING
130792cfeba6Schristos /* session tracking */
130892cfeba6Schristos if ( META_BACK_TGT_ST_REQUEST( mt ) ) {
130992cfeba6Schristos switch ( slap_ctrl_session_tracking_request_add( op, rs, &c[ j1 + j2 ] ) ) {
131092cfeba6Schristos case SLAP_CB_CONTINUE:
131192cfeba6Schristos break;
131292cfeba6Schristos
131392cfeba6Schristos case LDAP_SUCCESS:
131492cfeba6Schristos j2++;
131592cfeba6Schristos break;
131692cfeba6Schristos
131792cfeba6Schristos default:
131892cfeba6Schristos goto done;
131992cfeba6Schristos }
132092cfeba6Schristos }
132192cfeba6Schristos #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
132292cfeba6Schristos
132392cfeba6Schristos if ( rs->sr_err == SLAP_CB_CONTINUE ) {
132492cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
132592cfeba6Schristos }
132692cfeba6Schristos
132792cfeba6Schristos /* if nothing to do, just bail out */
132892cfeba6Schristos if ( j1 == 0 && j2 == 0 ) {
132992cfeba6Schristos goto done;
133092cfeba6Schristos }
133192cfeba6Schristos
133292cfeba6Schristos assert( j1 + j2 <= (int) (sizeof( c )/sizeof( c[0] )) );
133392cfeba6Schristos
133492cfeba6Schristos if ( op->o_ctrls ) {
133592cfeba6Schristos for ( n = 0; op->o_ctrls[ n ]; n++ )
133692cfeba6Schristos /* just count ctrls */ ;
133792cfeba6Schristos }
133892cfeba6Schristos
133992cfeba6Schristos ctrls = op->o_tmpalloc( (n + j1 + j2 + 1) * sizeof( LDAPControl * ) + ( j1 + j2 ) * sizeof( LDAPControl ),
134092cfeba6Schristos op->o_tmpmemctx );
134192cfeba6Schristos if ( j1 ) {
134292cfeba6Schristos ctrls[ 0 ] = (LDAPControl *)&ctrls[ n + j1 + j2 + 1 ];
134392cfeba6Schristos *ctrls[ 0 ] = c[ 0 ];
134492cfeba6Schristos for ( i = 1; i < j1; i++ ) {
134592cfeba6Schristos ctrls[ i ] = &ctrls[ 0 ][ i ];
134692cfeba6Schristos *ctrls[ i ] = c[ i ];
134792cfeba6Schristos }
134892cfeba6Schristos }
134992cfeba6Schristos
135092cfeba6Schristos i = 0;
135192cfeba6Schristos if ( op->o_ctrls ) {
135292cfeba6Schristos LDAPControl *proxyauthz = ldap_control_find(
135392cfeba6Schristos LDAP_CONTROL_PROXY_AUTHZ, op->o_ctrls, NULL );
135492cfeba6Schristos
135592cfeba6Schristos for ( i = 0; op->o_ctrls[ i ]; i++ ) {
135692cfeba6Schristos /* Only replace it if we generated one */
135792cfeba6Schristos if ( j1 && proxyauthz && proxyauthz == op->o_ctrls[ i ] ) {
135892cfeba6Schristos /* Frontend has already checked only one is present */
135992cfeba6Schristos assert( skipped == 0 );
136092cfeba6Schristos skipped++;
136192cfeba6Schristos continue;
136292cfeba6Schristos }
136392cfeba6Schristos ctrls[ i + j1 - skipped ] = op->o_ctrls[ i ];
136492cfeba6Schristos }
136592cfeba6Schristos }
136692cfeba6Schristos
136792cfeba6Schristos n += j1 - skipped;
136892cfeba6Schristos if ( j2 ) {
136992cfeba6Schristos ctrls[ n ] = (LDAPControl *)&ctrls[ n + j2 + 1 ] + j1;
137092cfeba6Schristos *ctrls[ n ] = c[ j1 ];
137192cfeba6Schristos for ( i = 1; i < j2; i++ ) {
137292cfeba6Schristos ctrls[ n + i ] = &ctrls[ n ][ i ];
137392cfeba6Schristos *ctrls[ n + i ] = c[ i ];
137492cfeba6Schristos }
137592cfeba6Schristos }
137692cfeba6Schristos
137792cfeba6Schristos ctrls[ n + j2 ] = NULL;
137892cfeba6Schristos
137992cfeba6Schristos done:;
138092cfeba6Schristos if ( ctrls == NULL ) {
138192cfeba6Schristos ctrls = op->o_ctrls;
138292cfeba6Schristos }
138392cfeba6Schristos
138492cfeba6Schristos *pctrls = ctrls;
138592cfeba6Schristos
138692cfeba6Schristos return rs->sr_err;
138792cfeba6Schristos }
138892cfeba6Schristos
138992cfeba6Schristos
139092cfeba6Schristos /*
139192cfeba6Schristos * asyncmeta_dobind_init()
139292cfeba6Schristos *
139392cfeba6Schristos * initiates bind for a candidate target
139492cfeba6Schristos */
139592cfeba6Schristos meta_search_candidate_t
asyncmeta_dobind_init(Operation * op,SlapReply * rs,bm_context_t * bc,a_metaconn_t * mc,int candidate)139692cfeba6Schristos asyncmeta_dobind_init(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
139792cfeba6Schristos {
139892cfeba6Schristos SlapReply *candidates = bc->candidates;
139992cfeba6Schristos a_metainfo_t *mi = ( a_metainfo_t * )mc->mc_info;
140092cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
140192cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[ candidate ];
140292cfeba6Schristos struct berval binddn = msc->msc_bound_ndn,
140392cfeba6Schristos cred = msc->msc_cred;
140492cfeba6Schristos int method;
140592cfeba6Schristos
140692cfeba6Schristos int rc;
140792cfeba6Schristos ber_int_t msgid;
140892cfeba6Schristos
140992cfeba6Schristos meta_search_candidate_t retcode;
141092cfeba6Schristos
141192cfeba6Schristos Debug( LDAP_DEBUG_TRACE, "%s >>> asyncmeta_dobind_init[%d] msc %p\n",
141292cfeba6Schristos op->o_log_prefix, candidate, msc );
141392cfeba6Schristos
141492cfeba6Schristos if ( mc->mc_authz_target == META_BOUND_ALL ) {
141592cfeba6Schristos return META_SEARCH_CANDIDATE;
141692cfeba6Schristos }
141792cfeba6Schristos
141892cfeba6Schristos if ( slapd_shutdown ) {
141992cfeba6Schristos rs->sr_err = LDAP_UNAVAILABLE;
142092cfeba6Schristos return META_SEARCH_ERR;
142192cfeba6Schristos }
142292cfeba6Schristos
142392cfeba6Schristos retcode = META_SEARCH_BINDING;
142492cfeba6Schristos if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
142592cfeba6Schristos /* already bound (or anonymous) */
142692cfeba6Schristos
142792cfeba6Schristos #ifdef DEBUG_205
142892cfeba6Schristos char buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
142992cfeba6Schristos int bound = 0;
143092cfeba6Schristos
143192cfeba6Schristos if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
143292cfeba6Schristos bound = 1;
143392cfeba6Schristos }
143492cfeba6Schristos
143592cfeba6Schristos Debug( LDAP_DEBUG_ANY,
143692cfeba6Schristos "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p%s DN=\"%s\"\n",
143792cfeba6Schristos op->o_log_prefix, candidate, (void *)mc,
143892cfeba6Schristos (void *)msc->msc_ld, bound ? " bound" : " anonymous",
143992cfeba6Schristos bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
144092cfeba6Schristos #endif /* DEBUG_205 */
144192cfeba6Schristos
144292cfeba6Schristos retcode = META_SEARCH_CANDIDATE;
144392cfeba6Schristos
144492cfeba6Schristos } else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
144592cfeba6Schristos /* another thread is binding the target for this conn; wait */
144692cfeba6Schristos
144792cfeba6Schristos #ifdef DEBUG_205
144892cfeba6Schristos
144992cfeba6Schristos Debug( LDAP_DEBUG_ANY,
145092cfeba6Schristos "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p needbind\n",
145192cfeba6Schristos op->o_log_prefix, candidate, (void *)mc,
145292cfeba6Schristos (void *)msc->msc_ld );
145392cfeba6Schristos #endif /* DEBUG_205 */
145492cfeba6Schristos
145592cfeba6Schristos candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
145692cfeba6Schristos retcode = META_SEARCH_NEED_BIND;
145792cfeba6Schristos } else {
145892cfeba6Schristos /* we'll need to bind the target for this conn */
145992cfeba6Schristos
146092cfeba6Schristos #ifdef DEBUG_205
146192cfeba6Schristos
146292cfeba6Schristos Debug( LDAP_DEBUG_ANY,
146392cfeba6Schristos "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p binding\n",
146492cfeba6Schristos op->o_log_prefix, candidate, (void *)mc,
146592cfeba6Schristos (void *)msc->msc_ld );
146692cfeba6Schristos #endif /* DEBUG_205 */
146792cfeba6Schristos
146892cfeba6Schristos if ( msc->msc_ld == NULL ) {
146992cfeba6Schristos /* for some reason (e.g. because formerly in "binding"
147092cfeba6Schristos * state, with eventual connection expiration or invalidation)
147192cfeba6Schristos * it was not initialized as expected */
147292cfeba6Schristos
147392cfeba6Schristos Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p ld=NULL\n",
147492cfeba6Schristos op->o_log_prefix, candidate, (void *)mc );
147592cfeba6Schristos
147692cfeba6Schristos rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
147792cfeba6Schristos LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
147892cfeba6Schristos
147992cfeba6Schristos switch ( rc ) {
148092cfeba6Schristos case LDAP_SUCCESS:
148192cfeba6Schristos assert( msc->msc_ld != NULL );
148292cfeba6Schristos break;
148392cfeba6Schristos
148492cfeba6Schristos case LDAP_SERVER_DOWN:
148592cfeba6Schristos case LDAP_UNAVAILABLE:
148692cfeba6Schristos goto down;
148792cfeba6Schristos
148892cfeba6Schristos default:
148992cfeba6Schristos goto other;
149092cfeba6Schristos }
149192cfeba6Schristos }
149292cfeba6Schristos
149392cfeba6Schristos LDAP_BACK_CONN_BINDING_SET( msc );
149492cfeba6Schristos }
149592cfeba6Schristos
149692cfeba6Schristos if ( retcode != META_SEARCH_BINDING ) {
149792cfeba6Schristos return retcode;
149892cfeba6Schristos }
149992cfeba6Schristos
150092cfeba6Schristos if ( op->o_conn != NULL &&
150192cfeba6Schristos !op->o_do_not_cache &&
150292cfeba6Schristos ( BER_BVISNULL( &msc->msc_bound_ndn ) ||
150392cfeba6Schristos BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
150492cfeba6Schristos ( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
150592cfeba6Schristos {
150692cfeba6Schristos rc = asyncmeta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
150792cfeba6Schristos switch ( rc ) {
150892cfeba6Schristos case LDAP_SUCCESS:
150992cfeba6Schristos break;
151092cfeba6Schristos case LDAP_UNAVAILABLE:
151192cfeba6Schristos goto down;
151292cfeba6Schristos default:
151392cfeba6Schristos goto other;
151492cfeba6Schristos }
151592cfeba6Schristos
151692cfeba6Schristos /* NOTE: we copy things here, even if bind didn't succeed yet,
151792cfeba6Schristos * because the connection is not shared until bind is over */
151892cfeba6Schristos if ( !BER_BVISNULL( &binddn ) ) {
151992cfeba6Schristos ber_bvreplace( &msc->msc_bound_ndn, &binddn );
152092cfeba6Schristos if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
152192cfeba6Schristos if ( !BER_BVISNULL( &msc->msc_cred ) ) {
152292cfeba6Schristos memset( msc->msc_cred.bv_val, 0,
152392cfeba6Schristos msc->msc_cred.bv_len );
152492cfeba6Schristos }
152592cfeba6Schristos ber_bvreplace( &msc->msc_cred, &cred );
152692cfeba6Schristos }
152792cfeba6Schristos }
152892cfeba6Schristos if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
152992cfeba6Schristos /* apparently, idassert was configured with SASL bind,
153092cfeba6Schristos * so bind occurred inside meta_back_proxy_authz_cred() */
153192cfeba6Schristos LDAP_BACK_CONN_BINDING_CLEAR( msc );
153292cfeba6Schristos return META_SEARCH_CANDIDATE;
153392cfeba6Schristos }
153492cfeba6Schristos
153592cfeba6Schristos /* paranoid */
153692cfeba6Schristos switch ( method ) {
153792cfeba6Schristos case LDAP_AUTH_NONE:
153892cfeba6Schristos case LDAP_AUTH_SIMPLE:
153992cfeba6Schristos /* do a simple bind with binddn, cred */
154092cfeba6Schristos break;
154192cfeba6Schristos
154292cfeba6Schristos default:
154392cfeba6Schristos assert( 0 );
154492cfeba6Schristos break;
154592cfeba6Schristos }
154692cfeba6Schristos }
154792cfeba6Schristos
154892cfeba6Schristos assert( msc->msc_ld != NULL );
154992cfeba6Schristos
155092cfeba6Schristos if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
155192cfeba6Schristos /* bind anonymously? */
155292cfeba6Schristos Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p: "
155392cfeba6Schristos "non-empty dn with empty cred; binding anonymously\n",
155492cfeba6Schristos op->o_log_prefix, candidate, (void *)mc );
155592cfeba6Schristos cred = slap_empty_bv;
155692cfeba6Schristos
155792cfeba6Schristos } else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
155892cfeba6Schristos /* error */
155992cfeba6Schristos Debug( LDAP_DEBUG_ANY, "%s asyncmeta_dobind_init[%d] mc=%p: "
156092cfeba6Schristos "empty dn with non-empty cred: error\n",
156192cfeba6Schristos op->o_log_prefix, candidate, (void *)mc );
156292cfeba6Schristos rc = LDAP_OTHER;
156392cfeba6Schristos goto other;
156492cfeba6Schristos }
156592cfeba6Schristos retry_bind:
156692cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
156792cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
156892cfeba6Schristos asyncmeta_get_timestamp(time_buf);
156992cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init sending bind msc: %p\n",
157092cfeba6Schristos time_buf, msc );
157192cfeba6Schristos }
157292cfeba6Schristos rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
157392cfeba6Schristos NULL, NULL, &msgid );
157492cfeba6Schristos ldap_get_option( msc->msc_ld, LDAP_OPT_RESULT_CODE, &rc );
157592cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
157692cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
157792cfeba6Schristos asyncmeta_get_timestamp(time_buf);
157892cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init rc=%d msc: %p\n",
157992cfeba6Schristos time_buf, rc, msc );
158092cfeba6Schristos }
158192cfeba6Schristos if ( LogTest( LDAP_DEBUG_TRACE )) {
158292cfeba6Schristos ber_socket_t s;
158392cfeba6Schristos char sockname[LDAP_IPADDRLEN];
158492cfeba6Schristos struct berval sockbv = BER_BVC( sockname );
158592cfeba6Schristos Sockaddr addr;
158692cfeba6Schristos socklen_t len = sizeof( addr );
158792cfeba6Schristos
158892cfeba6Schristos ldap_get_option( msc->msc_ld, LDAP_OPT_DESC, &s );
158992cfeba6Schristos getsockname( s, &addr.sa_addr, &len );
159092cfeba6Schristos ldap_pvt_sockaddrstr( &addr, &sockbv );
159192cfeba6Schristos Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_dobind_init msc %p ld %p ldr %p fd %d addr %s\n",
159292cfeba6Schristos op->o_log_prefix, msc, msc->msc_ld, msc->msc_ldr, s, sockname );
159392cfeba6Schristos }
159492cfeba6Schristos
159592cfeba6Schristos if (rc == LDAP_SERVER_DOWN ) {
159692cfeba6Schristos goto down;
159792cfeba6Schristos } else if (rc == LDAP_BUSY) {
159892cfeba6Schristos if (rs->sr_text == NULL) {
159992cfeba6Schristos rs->sr_text = "Unable to establish LDAP connection to target within the specified network timeout.";
160092cfeba6Schristos }
160192cfeba6Schristos LDAP_BACK_CONN_BINDING_CLEAR( msc );
160292cfeba6Schristos goto other;
160392cfeba6Schristos }
160492cfeba6Schristos /* mark as need bind so it gets send when the bind response is received */
160592cfeba6Schristos candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
160692cfeba6Schristos asyncmeta_set_msc_time(msc);
160792cfeba6Schristos #ifdef DEBUG_205
160892cfeba6Schristos Debug( LDAP_DEBUG_ANY,
160992cfeba6Schristos "### %s asyncmeta_dobind_init[%d] mc=%p ld=%p rc=%d\n",
161092cfeba6Schristos op->o_log_prefix, candidate, (void *)mc,
161192cfeba6Schristos (void *)mc->mc_conns[candidate].msc_ld, rc );
161292cfeba6Schristos #endif /* DEBUG_205 */
161392cfeba6Schristos
161492cfeba6Schristos switch ( rc ) {
161592cfeba6Schristos case LDAP_SUCCESS:
161692cfeba6Schristos assert( msgid >= 0 );
161792cfeba6Schristos if ( LogTest( asyncmeta_debug ) ) {
161892cfeba6Schristos char time_buf[ SLAP_TEXT_BUFLEN ];
161992cfeba6Schristos asyncmeta_get_timestamp(time_buf);
162092cfeba6Schristos Debug( asyncmeta_debug, "[%s] asyncmeta_dobind_init sending bind success msc: %p\n",
162192cfeba6Schristos time_buf, msc );
162292cfeba6Schristos }
162392cfeba6Schristos META_BINDING_SET( &candidates[ candidate ] );
162492cfeba6Schristos rs->sr_err = LDAP_SUCCESS;
162592cfeba6Schristos msc->msc_binding_time = slap_get_time();
162692cfeba6Schristos return META_SEARCH_BINDING;
162792cfeba6Schristos
162892cfeba6Schristos case LDAP_X_CONNECTING:
162992cfeba6Schristos /* must retry, same conn */
163092cfeba6Schristos candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
163192cfeba6Schristos LDAP_BACK_CONN_BINDING_CLEAR( msc );
163292cfeba6Schristos goto retry_bind;
163392cfeba6Schristos
163492cfeba6Schristos case LDAP_SERVER_DOWN:
163592cfeba6Schristos down:;
163692cfeba6Schristos retcode = META_SEARCH_ERR;
163792cfeba6Schristos rs->sr_err = LDAP_UNAVAILABLE;
163892cfeba6Schristos if (rs->sr_text == NULL) {
163992cfeba6Schristos rs->sr_text = "Unable to bind to remote target - target down or unavailable";
164092cfeba6Schristos }
164192cfeba6Schristos candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
164292cfeba6Schristos LDAP_BACK_CONN_BINDING_CLEAR( msc );
164392cfeba6Schristos break;
164492cfeba6Schristos
164592cfeba6Schristos /* fall thru */
164692cfeba6Schristos
164792cfeba6Schristos default:
164892cfeba6Schristos other:;
164992cfeba6Schristos rs->sr_err = rc;
165092cfeba6Schristos rc = slap_map_api2result( rs );
165192cfeba6Schristos candidates[ candidate ].sr_err = rc;
165292cfeba6Schristos if ( META_BACK_ONERR_STOP( mi ) ) {
165392cfeba6Schristos retcode = META_SEARCH_ERR;
165492cfeba6Schristos
165592cfeba6Schristos } else {
165692cfeba6Schristos retcode = META_SEARCH_NOT_CANDIDATE;
165792cfeba6Schristos }
165892cfeba6Schristos candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
165992cfeba6Schristos LDAP_BACK_CONN_BINDING_CLEAR( msc );
166092cfeba6Schristos break;
166192cfeba6Schristos }
166292cfeba6Schristos
166392cfeba6Schristos return retcode;
166492cfeba6Schristos }
166592cfeba6Schristos
166692cfeba6Schristos
166792cfeba6Schristos
166892cfeba6Schristos
166992cfeba6Schristos meta_search_candidate_t
asyncmeta_dobind_init_with_retry(Operation * op,SlapReply * rs,bm_context_t * bc,a_metaconn_t * mc,int candidate)167092cfeba6Schristos asyncmeta_dobind_init_with_retry(Operation *op, SlapReply *rs, bm_context_t *bc, a_metaconn_t *mc, int candidate)
167192cfeba6Schristos {
167292cfeba6Schristos
167392cfeba6Schristos int rc;
167492cfeba6Schristos a_metasingleconn_t *msc = &mc->mc_conns[candidate];
167592cfeba6Schristos a_metainfo_t *mi = mc->mc_info;
167692cfeba6Schristos a_metatarget_t *mt = mi->mi_targets[ candidate ];
167792cfeba6Schristos
167892cfeba6Schristos if (META_BACK_CONN_INVALID(msc) || (LDAP_BACK_CONN_BINDING( msc ) && msc->msc_binding_time > 0
167992cfeba6Schristos && (msc->msc_binding_time + mt->mt_timeout[ SLAP_OP_BIND ]) < slap_get_time())) {
168092cfeba6Schristos char buf[ SLAP_TEXT_BUFLEN ];
168192cfeba6Schristos snprintf( buf, sizeof( buf ), "called from %s:%d", __FILE__, __LINE__ );
168292cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
168392cfeba6Schristos asyncmeta_reset_msc(NULL, mc, candidate, 0, buf);
168492cfeba6Schristos
168592cfeba6Schristos rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
168692cfeba6Schristos LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
168792cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
168892cfeba6Schristos }
168992cfeba6Schristos
169092cfeba6Schristos if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
169192cfeba6Schristos if ( mc->pending_ops > 1 ) {
169292cfeba6Schristos asyncmeta_send_all_pending_ops( mc, candidate, op->o_threadctx, 1 );
169392cfeba6Schristos }
169492cfeba6Schristos return META_SEARCH_CANDIDATE;
169592cfeba6Schristos }
169692cfeba6Schristos
169792cfeba6Schristos retry_dobind:
169892cfeba6Schristos ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex );
169992cfeba6Schristos rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
170092cfeba6Schristos if (rs->sr_err != LDAP_UNAVAILABLE && rs->sr_err != LDAP_BUSY) {
170192cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
170292cfeba6Schristos return rc;
170392cfeba6Schristos } else if (bc->nretries[candidate] == 0) {
170492cfeba6Schristos char buf[ SLAP_TEXT_BUFLEN ];
170592cfeba6Schristos snprintf( buf, sizeof( buf ), "called from %s:%d", __FILE__, __LINE__ );
170692cfeba6Schristos asyncmeta_reset_msc(NULL, mc, candidate, 0, buf);
170792cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
170892cfeba6Schristos return rc;
170992cfeba6Schristos }
171092cfeba6Schristos /* need to retry */
171192cfeba6Schristos bc->nretries[candidate]--;
171292cfeba6Schristos if ( LogTest( LDAP_DEBUG_TRACE ) ) {
171392cfeba6Schristos /* this lock is required; however,
171492cfeba6Schristos * it's invoked only when logging is on */
171592cfeba6Schristos ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
171692cfeba6Schristos Debug( LDAP_DEBUG_ANY,
171792cfeba6Schristos "%s asyncmeta_dobind_init_with_retry[%d]: retrying URI=\"%s\" DN=\"%s\".\n",
171892cfeba6Schristos op->o_log_prefix, candidate, mt->mt_uri,
171992cfeba6Schristos BER_BVISNULL(&msc->msc_bound_ndn) ? "" : msc->msc_bound_ndn.bv_val );
172092cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );
172192cfeba6Schristos }
172292cfeba6Schristos
172392cfeba6Schristos asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
172492cfeba6Schristos rc = asyncmeta_init_one_conn( op, rs, mc, candidate,
172592cfeba6Schristos LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );
172692cfeba6Schristos
172792cfeba6Schristos if (rs->sr_err != LDAP_SUCCESS) {
172892cfeba6Schristos asyncmeta_reset_msc(NULL, mc, candidate, 0, __FUNCTION__);
172992cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
173092cfeba6Schristos return META_SEARCH_ERR;
173192cfeba6Schristos }
173292cfeba6Schristos ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex );
173392cfeba6Schristos goto retry_dobind;
173492cfeba6Schristos return rc;
173592cfeba6Schristos }
1736