/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1999-2005 The OpenLDAP Foundation.
+ * Copyright 1999-2006 The OpenLDAP Foundation.
* Portions Copyright 2000-2003 Pierangelo Masarati.
* Portions Copyright 1999-2003 Howard Chu.
* All rights reserved.
LDAP_REBIND_PROC *ldap_back_rebind_f = ldap_back_default_rebind;
static int
-ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs );
+ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
static int
ldap_back_prepare_conn( ldapconn_t **lcp, Operation *op, SlapReply *rs, ldap_back_send_t sendok );
int rc = 0;
ber_int_t msgid;
- lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR );
+ lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR );
if ( !lc ) {
return rs->sr_err;
}
* bind with the configured identity assertion */
/* NOTE: use with care */
if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
- ldap_back_proxy_authz_bind( lc, op, rs );
+ ldap_back_proxy_authz_bind( lc, op, rs, LDAP_BACK_SENDERR );
if ( !LDAP_BACK_CONN_ISBOUND( lc ) ) {
rc = 1;
goto done;
rc = ldap_install_tls( ld );
} else if ( rc == LDAP_REFERRAL ) {
- rc = LDAP_OTHER;
+ rc = LDAP_UNWILLING_TO_PERFORM;
*text = "unwilling to chase referral returned by Start TLS exop";
}
/* Set LDAP version. This will always succeed: If the client
* bound with a particular version, then so can we.
*/
+ if ( vers == 0 ) {
+ /* assume it's an internal op; set to LDAPv3 */
+ vers = LDAP_VERSION3;
+ }
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&vers );
/* automatically chase referrals ("[dont-]chase-referrals" statement) */
ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- ldapconn_t *lc,
+ ldapconn_t *lc = NULL,
lc_curr = { 0 };
int refcnt = 1;
}
}
- /* Searches for a ldapconn in the avl tree */
- ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ /* Explicit Bind requests always get their own conn */
+ if ( !( sendok & LDAP_BACK_BINDING ) ) {
+ /* Searches for a ldapconn in the avl tree */
+retry_lock:
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
- lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
- (caddr_t)&lc_curr, ldap_back_conn_cmp );
- if ( lc != NULL ) {
- refcnt = ++lc->lc_refcnt;
+ lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree,
+ (caddr_t)&lc_curr, ldap_back_conn_cmp );
+ if ( lc != NULL ) {
+ /* Don't reuse connections while they're still binding */
+ if ( LDAP_BACK_CONN_BINDING( lc ) ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ ldap_pvt_thread_yield();
+ goto retry_lock;
+ }
+ refcnt = ++lc->lc_refcnt;
+ }
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
}
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
/* Looks like we didn't get a bind. Open a new session... */
if ( lc == NULL ) {
if ( ldap_back_prepare_conn( &lc, op, rs, sendok ) != LDAP_SUCCESS ) {
return NULL;
}
-
+ if ( sendok & LDAP_BACK_BINDING ) {
+ LDAP_BACK_CONN_BINDING_SET( lc );
+ }
lc->lc_conn = lc_curr.lc_conn;
ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
}
void
-ldap_back_release_conn(
+ldap_back_release_conn_lock(
Operation *op,
SlapReply *rs,
- ldapconn_t *lc )
+ ldapconn_t *lc,
+ int dolock )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
- ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ }
assert( lc->lc_refcnt > 0 );
lc->lc_refcnt--;
- ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ LDAP_BACK_CONN_BINDING_CLEAR( lc );
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
}
/*
return rc;
}
+ while ( lc->lc_refcnt > 1 ) {
+ ldap_pvt_thread_yield();
+ rc = LDAP_BACK_CONN_ISBOUND( lc );
+ if ( rc ) {
+ return rc;
+ }
+ }
+
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
+ }
+ LDAP_BACK_CONN_BINDING_SET( lc );
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
+ }
+
/*
* FIXME: we need to let clients use proxyAuthz
* otherwise we cannot do symmetric pools of servers;
( BER_BVISNULL( &lc->lc_bound_ndn ) ||
( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
{
- (void)ldap_back_proxy_authz_bind( lc, op, rs );
+ (void)ldap_back_proxy_authz_bind( lc, op, rs, sendok );
goto done;
}
rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
-
- } else {
- ldap_back_release_conn( op, rs, lc );
}
done:;
+ LDAP_BACK_CONN_BINDING_CLEAR( lc );
rc = LDAP_BACK_CONN_ISBOUND( lc );
+ if ( !rc ) {
+ ldap_back_release_conn_lock( op, rs, lc, dolock );
+ }
return rc;
}
retry:;
/* if result parsing fails, note the failure reason */
- rc = ldap_result( lc->lc_ld, msgid, 1, &tv, &res );
+ rc = ldap_result( lc->lc_ld, msgid, LDAP_MSG_ALL, &tv, &res );
switch ( rc ) {
case 0:
if ( timeout ) {
}
static int
-ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs )
+ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
{
ldapinfo_t *li = (ldapinfo_t *)op->o_bd->be_private;
struct berval binddn = slap_empty_bv;
struct berval bindcred = slap_empty_bv;
+ struct berval ndn;
int dobind = 0;
int msgid;
int rc;
+ if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ ndn = op->o_conn->c_ndn;
+
+ } else {
+ ndn = op->o_ndn;
+ }
+
/*
* FIXME: we need to let clients use proxyAuthz
* otherwise we cannot do symmetric pools of servers;
* is authorized */
switch ( li->li_idassert_mode ) {
case LDAP_BACK_IDASSERT_LEGACY:
- if ( !BER_BVISNULL( &op->o_conn->c_ndn ) && !BER_BVISEMPTY( &op->o_conn->c_ndn ) ) {
+ if ( !BER_BVISNULL( &ndn ) && !BER_BVISEMPTY( &ndn ) ) {
if ( !BER_BVISNULL( &li->li_idassert_authcDN ) && !BER_BVISEMPTY( &li->li_idassert_authcDN ) )
{
binddn = li->li_idassert_authcDN;
default:
/* NOTE: rootdn can always idassert */
- if ( li->li_idassert_authz && !be_isroot( op ) ) {
+ if ( BER_BVISNULL( &ndn ) && li->li_idassert_authz == NULL ) {
+ if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
+ rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
+ LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
+
+ } else {
+ rs->sr_err = LDAP_SUCCESS;
+ binddn = slap_empty_bv;
+ bindcred = slap_empty_bv;
+ break;
+ }
+
+ goto done;
+
+ } else if ( li->li_idassert_authz && !be_isroot( op ) ) {
struct berval authcDN;
- if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ if ( BER_BVISNULL( &ndn ) ) {
authcDN = slap_empty_bv;
} else {
- authcDN = op->o_conn->c_ndn;
+ authcDN = ndn;
}
rs->sr_err = slap_sasl_matches( op, li->li_idassert_authz,
&authcDN, &authcDN );
if ( rs->sr_err != LDAP_SUCCESS ) {
if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) {
- send_ldap_result( op, rs );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
} else {
break;
case LDAP_BACK_IDASSERT_SELF:
- if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ if ( BER_BVISNULL( &ndn ) ) {
/* connection is not authc'd, so don't idassert */
BER_BVSTR( &authzID, "dn:" );
break;
}
- authzID.bv_len = STRLENOF( "dn:" ) + op->o_conn->c_ndn.bv_len;
+ authzID.bv_len = STRLENOF( "dn:" ) + ndn.bv_len;
authzID.bv_val = slap_sl_malloc( authzID.bv_len + 1, op->o_tmpmemctx );
AC_MEMCPY( authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
AC_MEMCPY( authzID.bv_val + STRLENOF( "dn:" ),
- op->o_conn->c_ndn.bv_val, op->o_conn->c_ndn.bv_len + 1 );
+ ndn.bv_val, ndn.bv_len + 1 );
freeauthz = 1;
break;
(void *)li->li_idassert_secprops );
if ( rs->sr_err != LDAP_OPT_SUCCESS ) {
- send_ldap_result( op, rs );
+ rs->sr_err = LDAP_OTHER;
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
goto done;
}
rs->sr_err = slap_map_api2result( rs );
if ( rs->sr_err != LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
- send_ldap_result( op, rs );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
} else {
LDAP_BACK_CONN_ISBOUND_SET( lc );
/* unsupported! */
LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
rs->sr_err = LDAP_AUTH_METHOD_NOT_SUPPORTED;
- send_ldap_result( op, rs );
+ if ( sendok & LDAP_BACK_SENDERR ) {
+ send_ldap_result( op, rs );
+ }
goto done;
}
- rc = ldap_back_op_result( lc, op, rs, msgid, 0, LDAP_BACK_SENDERR );
+ rc = ldap_back_op_result( lc, op, rs, msgid, 0, sendok );
if ( rc == LDAP_SUCCESS ) {
LDAP_BACK_CONN_ISBOUND_SET( lc );
}
LDAPControl **ctrls = NULL;
int i = 0,
mode;
- struct berval assertedID;
+ struct berval assertedID,
+ ndn;
*pctrls = NULL;
goto done;
}
+ if ( !BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ ndn = op->o_conn->c_ndn;
+
+ } else {
+ ndn = op->o_ndn;
+ }
+
if ( li->li_idassert_mode == LDAP_BACK_IDASSERT_LEGACY ) {
if ( op->o_proxy_authz ) {
/*
goto done;
}
- if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ if ( BER_BVISNULL( &ndn ) ) {
goto done;
}
} else if ( li->li_idassert_authmethod == LDAP_AUTH_SASL ) {
if ( ( li->li_idassert_flags & LDAP_BACK_AUTH_NATIVE_AUTHZ )
- /* && ( !BER_BVISNULL( &op->o_conn->c_ndn )
+ /* && ( !BER_BVISNULL( &ndn )
|| LDAP_BACK_CONN_ISBOUND( lc ) ) */ )
{
/* already asserted in SASL via native authz */
/* NOTE: the test on lc->lc_bound is used to trap
* native authorization of anonymous users,
- * since in that case op->o_conn->c_ndn is NULL */
+ * since in that case ndn is NULL */
goto done;
}
int rc;
struct berval authcDN;
- if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ if ( BER_BVISNULL( &ndn ) ) {
authcDN = slap_empty_bv;
} else {
- authcDN = op->o_conn->c_ndn;
+ authcDN = ndn;
}
rc = slap_sasl_matches( op, li->li_idassert_authz,
&authcDN, & authcDN );
if ( rc != LDAP_SUCCESS ) {
if ( li->li_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE )
{
- /* op->o_conn->c_ndn is not authorized
+ /* ndn is not authorized
* to use idassert */
return rc;
}
}
switch ( mode ) {
- case LDAP_BACK_IDASSERT_LEGACY:
case LDAP_BACK_IDASSERT_SELF:
+ if ( BER_BVISNULL( &ndn ) ) {
+ goto done;
+ }
+ assertedID = ndn;
+ break;
+
+ case LDAP_BACK_IDASSERT_LEGACY:
/* original behavior:
* assert the client's identity */
- if ( BER_BVISNULL( &op->o_conn->c_ndn ) ) {
+ if ( BER_BVISNULL( &ndn ) ) {
assertedID = slap_empty_bv;
} else {
- assertedID = op->o_conn->c_ndn;
+ assertedID = ndn;
}
break;
/* just count ctrls */ ;
}
- ctrls = ch_malloc( sizeof( LDAPControl * ) * (i + 2) );
- ctrls[ 0 ] = ch_malloc( sizeof( LDAPControl ) );
+ ctrls = op->o_tmpalloc( sizeof( LDAPControl * ) * (i + 2) + sizeof( LDAPControl ),
+ op->o_tmpmemctx );
+ ctrls[ 0 ] = (LDAPControl *)&ctrls[ i + 2 ];
ctrls[ 0 ]->ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
ctrls[ 0 ]->ldctl_iscritical = 1;
/* already in u:ID or dn:DN form */
case LDAP_BACK_IDASSERT_OTHERID:
case LDAP_BACK_IDASSERT_OTHERDN:
- ber_dupbv( &ctrls[ 0 ]->ldctl_value, &assertedID );
+ ber_dupbv_x( &ctrls[ 0 ]->ldctl_value, &assertedID, op->o_tmpmemctx );
break;
/* needs the dn: prefix */
default:
ctrls[ 0 ]->ldctl_value.bv_len = assertedID.bv_len + STRLENOF( "dn:" );
- ctrls[ 0 ]->ldctl_value.bv_val = ch_malloc( ctrls[ 0 ]->ldctl_value.bv_len + 1 );
+ ctrls[ 0 ]->ldctl_value.bv_val = op->o_tmpalloc( ctrls[ 0 ]->ldctl_value.bv_len + 1,
+ op->o_tmpmemctx );
AC_MEMCPY( ctrls[ 0 ]->ldctl_value.bv_val, "dn:", STRLENOF( "dn:" ) );
AC_MEMCPY( &ctrls[ 0 ]->ldctl_value.bv_val[ STRLENOF( "dn:" ) ],
assertedID.bv_val, assertedID.bv_len + 1 );
assert( ctrls[ 0 ] != NULL );
if ( !BER_BVISNULL( &ctrls[ 0 ]->ldctl_value ) ) {
- free( ctrls[ 0 ]->ldctl_value.bv_val );
+ op->o_tmpfree( ctrls[ 0 ]->ldctl_value.bv_val, op->o_tmpmemctx );
}
- free( ctrls[ 0 ] );
- free( ctrls );
+ op->o_tmpfree( ctrls, op->o_tmpmemctx );
}
*pctrls = NULL;