mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-21 07:09:34 -05:00
Add ldap_sasl_interactive_bind()
This commit is contained in:
parent
0b660dc9f6
commit
fca72f333b
4 changed files with 230 additions and 191 deletions
|
|
@ -1186,6 +1186,26 @@ ldap_sasl_bind LDAP_P((
|
||||||
typedef int (LDAP_SASL_INTERACT_PROC) LDAP_P((
|
typedef int (LDAP_SASL_INTERACT_PROC) LDAP_P((
|
||||||
LDAP *ld, unsigned flags, void* defaults, void *interact ));
|
LDAP *ld, unsigned flags, void* defaults, void *interact ));
|
||||||
|
|
||||||
|
LDAP_F( int )
|
||||||
|
ldap_sasl_interactive_bind LDAP_P((
|
||||||
|
LDAP *ld,
|
||||||
|
LDAP_CONST char *dn, /* usually NULL */
|
||||||
|
LDAP_CONST char *saslMechanism,
|
||||||
|
LDAPControl **serverControls,
|
||||||
|
LDAPControl **clientControls,
|
||||||
|
|
||||||
|
/* should be client controls */
|
||||||
|
unsigned flags,
|
||||||
|
LDAP_SASL_INTERACT_PROC *proc,
|
||||||
|
void *defaults,
|
||||||
|
|
||||||
|
/* as obtained from ldap_result() */
|
||||||
|
LDAPMessage *result,
|
||||||
|
|
||||||
|
/* returned during bind processing */
|
||||||
|
const char **rmech,
|
||||||
|
int *msgid ));
|
||||||
|
|
||||||
LDAP_F( int )
|
LDAP_F( int )
|
||||||
ldap_sasl_interactive_bind_s LDAP_P((
|
ldap_sasl_interactive_bind_s LDAP_P((
|
||||||
LDAP *ld,
|
LDAP *ld,
|
||||||
|
|
|
||||||
|
|
@ -386,19 +386,18 @@ ldap_int_sasl_bind(
|
||||||
LDAPControl **cctrls,
|
LDAPControl **cctrls,
|
||||||
unsigned flags,
|
unsigned flags,
|
||||||
LDAP_SASL_INTERACT_PROC *interact,
|
LDAP_SASL_INTERACT_PROC *interact,
|
||||||
void * defaults )
|
void *defaults,
|
||||||
|
LDAPMessage *result,
|
||||||
|
const char **rmech,
|
||||||
|
int *msgid )
|
||||||
{
|
{
|
||||||
char *data;
|
const char *mech;
|
||||||
const char *mech = NULL;
|
sasl_ssf_t *ssf;
|
||||||
const char *pmech = NULL;
|
sasl_conn_t *ctx;
|
||||||
int saslrc, rc;
|
|
||||||
sasl_ssf_t *ssf = NULL;
|
|
||||||
sasl_conn_t *ctx, *oldctx = NULL;
|
|
||||||
sasl_interact_t *prompts = NULL;
|
sasl_interact_t *prompts = NULL;
|
||||||
unsigned credlen;
|
|
||||||
struct berval ccred;
|
struct berval ccred;
|
||||||
ber_socket_t sd;
|
int saslrc, rc;
|
||||||
void *ssl;
|
unsigned credlen;
|
||||||
|
|
||||||
Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
|
Debug( LDAP_DEBUG_TRACE, "ldap_int_sasl_bind: %s\n",
|
||||||
mechs ? mechs : "<null>", 0, 0 );
|
mechs ? mechs : "<null>", 0, 0 );
|
||||||
|
|
@ -409,6 +408,13 @@ ldap_int_sasl_bind(
|
||||||
return ld->ld_errno;
|
return ld->ld_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Starting a Bind */
|
||||||
|
if ( !result ) {
|
||||||
|
const char *pmech = NULL;
|
||||||
|
sasl_conn_t *oldctx;
|
||||||
|
ber_socket_t sd;
|
||||||
|
void *ssl;
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
|
LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
|
||||||
ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
|
ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, &sd );
|
||||||
|
|
@ -500,6 +506,7 @@ ldap_int_sasl_bind(
|
||||||
|
|
||||||
ccred.bv_val = NULL;
|
ccred.bv_val = NULL;
|
||||||
ccred.bv_len = 0;
|
ccred.bv_len = 0;
|
||||||
|
mech = NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
saslrc = sasl_client_start( ctx,
|
saslrc = sasl_client_start( ctx,
|
||||||
|
|
@ -529,83 +536,33 @@ ldap_int_sasl_bind(
|
||||||
|
|
||||||
if( res != LDAP_SUCCESS ) break;
|
if( res != LDAP_SUCCESS ) break;
|
||||||
}
|
}
|
||||||
|
*rmech = mech;
|
||||||
} while ( saslrc == SASL_INTERACT );
|
} while ( saslrc == SASL_INTERACT );
|
||||||
|
|
||||||
ccred.bv_len = credlen;
|
} else {
|
||||||
|
/* continuing an in-progress Bind */
|
||||||
if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
|
struct berval *scred = NULL;
|
||||||
rc = ld->ld_errno = sasl_err2ldap( saslrc );
|
|
||||||
#if SASL_VERSION_MAJOR >= 2
|
|
||||||
if ( ld->ld_error ) {
|
|
||||||
LDAP_FREE( ld->ld_error );
|
|
||||||
}
|
|
||||||
ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
|
|
||||||
#endif
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct berval *scred;
|
|
||||||
unsigned credlen;
|
|
||||||
|
|
||||||
scred = NULL;
|
scred = NULL;
|
||||||
|
rc = ldap_parse_sasl_bind_result( ld, result, &scred, 0 );
|
||||||
|
if ( rc != LDAP_SUCCESS )
|
||||||
|
goto done;
|
||||||
|
|
||||||
rc = ldap_sasl_bind_s( ld, dn, mech, &ccred, sctrls, cctrls,
|
rc = ldap_result2error( ld, result, 0 );
|
||||||
&scred );
|
|
||||||
|
|
||||||
if ( ccred.bv_val != NULL ) {
|
|
||||||
#if SASL_VERSION_MAJOR < 2
|
|
||||||
LDAP_FREE( ccred.bv_val );
|
|
||||||
#endif
|
|
||||||
ccred.bv_val = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
|
if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
|
||||||
if( scred ) {
|
if( scred ) {
|
||||||
/* and server provided us with data? */
|
/* and server provided us with data? */
|
||||||
Debug( LDAP_DEBUG_TRACE,
|
Debug( LDAP_DEBUG_TRACE,
|
||||||
"ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
|
"ldap_int_sasl_bind: rc=%d len=%ld\n",
|
||||||
rc, saslrc, scred ? (long) scred->bv_len : -1L );
|
rc, scred ? (long) scred->bv_len : -1L, 0 );
|
||||||
ber_bvfree( scred );
|
ber_bvfree( scred );
|
||||||
scred = NULL;
|
scred = NULL;
|
||||||
}
|
}
|
||||||
rc = ld->ld_errno;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
|
ctx = ld->ld_defconn->lconn_sasl_authctx;
|
||||||
/* we're done, no need to step */
|
mech = *rmech;
|
||||||
if( scred ) {
|
|
||||||
/* but we got additional data? */
|
|
||||||
#define KLUDGE_FOR_MSAD
|
|
||||||
#ifdef KLUDGE_FOR_MSAD
|
|
||||||
/*
|
|
||||||
* MSAD provides empty additional data in violation of LDAP
|
|
||||||
* technical specifications. As no existing SASL mechanism
|
|
||||||
* allows empty data with an outcome message, just ignore it
|
|
||||||
* for now. Hopefully MS will fix their bug before someone
|
|
||||||
* defines a mechanism with possibly empty additional data.
|
|
||||||
*/
|
|
||||||
if( scred->bv_len == 0 ) {
|
|
||||||
Debug( LDAP_DEBUG_ANY,
|
|
||||||
"ldap_int_sasl_bind: ignoring "
|
|
||||||
" bogus empty data provided with SASL outcome message.\n",
|
|
||||||
rc, saslrc, scred->bv_len );
|
|
||||||
ber_bvfree( scred );
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Debug( LDAP_DEBUG_TRACE,
|
|
||||||
"ldap_int_sasl_bind: rc=%d sasl=%d len=%ld\n",
|
|
||||||
rc, saslrc, scred->bv_len );
|
|
||||||
rc = ld->ld_errno = LDAP_LOCAL_ERROR;
|
|
||||||
ber_bvfree( scred );
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if( ! scred ) {
|
if( ! scred ) {
|
||||||
/* no data! */
|
/* no data! */
|
||||||
|
|
@ -632,36 +589,42 @@ ldap_int_sasl_bind(
|
||||||
}
|
}
|
||||||
} while ( saslrc == SASL_INTERACT );
|
} while ( saslrc == SASL_INTERACT );
|
||||||
|
|
||||||
ccred.bv_len = credlen;
|
|
||||||
ber_bvfree( scred );
|
ber_bvfree( scred );
|
||||||
|
}
|
||||||
|
|
||||||
if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
|
if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
|
||||||
ld->ld_errno = sasl_err2ldap( saslrc );
|
|
||||||
#if SASL_VERSION_MAJOR >= 2
|
|
||||||
if ( ld->ld_error ) {
|
|
||||||
LDAP_FREE( ld->ld_error );
|
|
||||||
}
|
|
||||||
ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
|
|
||||||
#endif
|
|
||||||
rc = ld->ld_errno;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
|
|
||||||
|
|
||||||
if ( rc != LDAP_SUCCESS ) goto done;
|
|
||||||
|
|
||||||
if ( saslrc != SASL_OK ) {
|
|
||||||
#if SASL_VERSION_MAJOR >= 2
|
|
||||||
if ( ld->ld_error ) {
|
|
||||||
LDAP_FREE( ld->ld_error );
|
|
||||||
}
|
|
||||||
ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
|
|
||||||
#endif
|
|
||||||
rc = ld->ld_errno = sasl_err2ldap( saslrc );
|
rc = ld->ld_errno = sasl_err2ldap( saslrc );
|
||||||
|
#if SASL_VERSION_MAJOR >= 2
|
||||||
|
if ( ld->ld_error ) {
|
||||||
|
LDAP_FREE( ld->ld_error );
|
||||||
|
}
|
||||||
|
ld->ld_error = LDAP_STRDUP( sasl_errdetail( ctx ) );
|
||||||
|
#endif
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccred.bv_len = credlen;
|
||||||
|
|
||||||
|
/* Always send a request on first Bind; only send subsequent if
|
||||||
|
* saslrc == SASL_CONTINUE
|
||||||
|
*/
|
||||||
|
if ( !result || saslrc == SASL_CONTINUE ) {
|
||||||
|
rc = ldap_sasl_bind( ld, dn, mech, &ccred, sctrls, cctrls, msgid );
|
||||||
|
|
||||||
|
if ( ccred.bv_val != NULL ) {
|
||||||
|
#if SASL_VERSION_MAJOR < 2
|
||||||
|
LDAP_FREE( ccred.bv_val );
|
||||||
|
#endif
|
||||||
|
ccred.bv_val = NULL;
|
||||||
|
}
|
||||||
|
if ( rc == LDAP_SUCCESS )
|
||||||
|
rc = LDAP_SASL_BIND_IN_PROGRESS;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Conversation was completed successfully by now */
|
||||||
if( flags != LDAP_SASL_QUIET ) {
|
if( flags != LDAP_SASL_QUIET ) {
|
||||||
|
char *data;
|
||||||
saslrc = sasl_getprop( ctx, SASL_USERNAME,
|
saslrc = sasl_getprop( ctx, SASL_USERNAME,
|
||||||
(SASL_CONST void **)(char *) &data );
|
(SASL_CONST void **)(char *) &data );
|
||||||
if( saslrc == SASL_OK && data && *data ) {
|
if( saslrc == SASL_OK && data && *data ) {
|
||||||
|
|
@ -677,6 +640,7 @@ ldap_int_sasl_bind(
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssf = NULL;
|
||||||
saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **)(char *) &ssf );
|
saslrc = sasl_getprop( ctx, SASL_SSF, (SASL_CONST void **)(char *) &ssf );
|
||||||
if( saslrc == SASL_OK ) {
|
if( saslrc == SASL_OK ) {
|
||||||
if( flags != LDAP_SASL_QUIET ) {
|
if( flags != LDAP_SASL_QUIET ) {
|
||||||
|
|
@ -686,7 +650,7 @@ ldap_int_sasl_bind(
|
||||||
|
|
||||||
if( ssf && *ssf ) {
|
if( ssf && *ssf ) {
|
||||||
if ( ld->ld_defconn->lconn_sasl_sockctx ) {
|
if ( ld->ld_defconn->lconn_sasl_sockctx ) {
|
||||||
oldctx = ld->ld_defconn->lconn_sasl_sockctx;
|
sasl_conn_t *oldctx = ld->ld_defconn->lconn_sasl_sockctx;
|
||||||
sasl_dispose( &oldctx );
|
sasl_dispose( &oldctx );
|
||||||
ldap_pvt_sasl_remove( ld->ld_defconn->lconn_sb );
|
ldap_pvt_sasl_remove( ld->ld_defconn->lconn_sb );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -685,7 +685,10 @@ LDAP_F (int) ldap_int_sasl_bind LDAP_P((
|
||||||
/* should be passed in client controls */
|
/* should be passed in client controls */
|
||||||
unsigned flags,
|
unsigned flags,
|
||||||
LDAP_SASL_INTERACT_PROC *interact,
|
LDAP_SASL_INTERACT_PROC *interact,
|
||||||
void *defaults ));
|
void *defaults,
|
||||||
|
LDAPMessage *result,
|
||||||
|
const char **rmech,
|
||||||
|
int *msgid ));
|
||||||
|
|
||||||
/* in schema.c */
|
/* in schema.c */
|
||||||
LDAP_F (char *) ldap_int_parse_numericoid LDAP_P((
|
LDAP_F (char *) ldap_int_parse_numericoid LDAP_P((
|
||||||
|
|
|
||||||
|
|
@ -401,15 +401,16 @@ ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ldap_sasl_interactive_bind_s - interactive SASL authentication
|
* ldap_sasl_interactive_bind - interactive SASL authentication
|
||||||
*
|
*
|
||||||
* This routine uses interactive callbacks.
|
* This routine uses interactive callbacks.
|
||||||
*
|
*
|
||||||
* LDAP_SUCCESS is returned upon success, the ldap error code
|
* LDAP_SUCCESS is returned upon success, the ldap error code
|
||||||
* otherwise.
|
* otherwise. LDAP_SASL_BIND_IN_PROGRESS is returned if further
|
||||||
|
* calls are needed.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ldap_sasl_interactive_bind_s(
|
ldap_sasl_interactive_bind(
|
||||||
LDAP *ld,
|
LDAP *ld,
|
||||||
LDAP_CONST char *dn, /* usually NULL */
|
LDAP_CONST char *dn, /* usually NULL */
|
||||||
LDAP_CONST char *mechs,
|
LDAP_CONST char *mechs,
|
||||||
|
|
@ -417,10 +418,13 @@ ldap_sasl_interactive_bind_s(
|
||||||
LDAPControl **clientControls,
|
LDAPControl **clientControls,
|
||||||
unsigned flags,
|
unsigned flags,
|
||||||
LDAP_SASL_INTERACT_PROC *interact,
|
LDAP_SASL_INTERACT_PROC *interact,
|
||||||
void *defaults )
|
void *defaults,
|
||||||
|
LDAPMessage *result,
|
||||||
|
const char **rmech,
|
||||||
|
int *msgid )
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
char *smechs = NULL;
|
char *smechs = NULL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
#if defined( HAVE_CYRUS_SASL )
|
#if defined( HAVE_CYRUS_SASL )
|
||||||
LDAP_MUTEX_LOCK( &ldap_int_sasl_mutex );
|
LDAP_MUTEX_LOCK( &ldap_int_sasl_mutex );
|
||||||
|
|
@ -437,6 +441,9 @@ ldap_sasl_interactive_bind_s(
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* First time */
|
||||||
|
if ( !result ) {
|
||||||
|
|
||||||
#ifdef HAVE_CYRUS_SASL
|
#ifdef HAVE_CYRUS_SASL
|
||||||
if( mechs == NULL || *mechs == '\0' ) {
|
if( mechs == NULL || *mechs == '\0' ) {
|
||||||
mechs = ld->ld_options.ldo_def_sasl_mech;
|
mechs = ld->ld_options.ldo_def_sasl_mech;
|
||||||
|
|
@ -460,10 +467,10 @@ ldap_sasl_interactive_bind_s(
|
||||||
"ldap_sasl_interactive_bind_s: user selected: %s\n",
|
"ldap_sasl_interactive_bind_s: user selected: %s\n",
|
||||||
mechs, 0, 0 );
|
mechs, 0, 0 );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
rc = ldap_int_sasl_bind( ld, dn, mechs,
|
rc = ldap_int_sasl_bind( ld, dn, mechs,
|
||||||
serverControls, clientControls,
|
serverControls, clientControls,
|
||||||
flags, interact, defaults );
|
flags, interact, defaults, result, rmech, msgid );
|
||||||
|
|
||||||
done:
|
done:
|
||||||
#if defined( HAVE_CYRUS_SASL )
|
#if defined( HAVE_CYRUS_SASL )
|
||||||
|
|
@ -474,6 +481,51 @@ done:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ldap_sasl_interactive_bind_s - interactive SASL authentication
|
||||||
|
*
|
||||||
|
* This routine uses interactive callbacks.
|
||||||
|
*
|
||||||
|
* LDAP_SUCCESS is returned upon success, the ldap error code
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ldap_sasl_interactive_bind_s(
|
||||||
|
LDAP *ld,
|
||||||
|
LDAP_CONST char *dn, /* usually NULL */
|
||||||
|
LDAP_CONST char *mechs,
|
||||||
|
LDAPControl **serverControls,
|
||||||
|
LDAPControl **clientControls,
|
||||||
|
unsigned flags,
|
||||||
|
LDAP_SASL_INTERACT_PROC *interact,
|
||||||
|
void *defaults )
|
||||||
|
{
|
||||||
|
const char *rmech = NULL;
|
||||||
|
LDAPMessage *result = NULL;
|
||||||
|
int rc, msgid;
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc = ldap_sasl_interactive_bind( ld, dn, mechs,
|
||||||
|
serverControls, clientControls,
|
||||||
|
flags, interact, defaults, result, &rmech, &msgid );
|
||||||
|
|
||||||
|
if ( rc != LDAP_SASL_BIND_IN_PROGRESS )
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef LDAP_CONNECTIONLESS
|
||||||
|
if (LDAP_IS_UDP(ld)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
|
||||||
|
return( ld->ld_errno ); /* ldap_result sets ld_errno */
|
||||||
|
}
|
||||||
|
} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CYRUS_SASL
|
#ifdef HAVE_CYRUS_SASL
|
||||||
|
|
||||||
#ifdef HAVE_SASL_SASL_H
|
#ifdef HAVE_SASL_SASL_H
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue