bugzilla%standard8.plus.com 528338f962 Bug 511817 Malformed Packet appears in network trace of SASL binding. p=Xu Qiang <Qiang.Xu@fujixerox.com>,r=richm
git-svn-id: svn://10.0.0.236/trunk@258585 18797224-902f-48f8-a5cc-f745e15eee43
2009-10-04 20:42:09 +00:00

878 lines
28 KiB
C

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "ldap-int.h"
#ifdef LDAP_SASLIO_HOOKS
/*
* Global SASL Init data
*/
static int
nsldapi_sasl_fail()
{
return( SASL_FAIL );
}
sasl_callback_t client_callbacks[] = {
{ SASL_CB_GETOPT, nsldapi_sasl_fail, NULL },
{ SASL_CB_GETREALM, NULL, NULL },
{ SASL_CB_USER, NULL, NULL },
{ SASL_CB_CANON_USER, NULL, NULL },
{ SASL_CB_AUTHNAME, NULL, NULL },
{ SASL_CB_PASS, NULL, NULL },
{ SASL_CB_ECHOPROMPT, NULL, NULL },
{ SASL_CB_NOECHOPROMPT, NULL, NULL },
{ SASL_CB_LIST_END, NULL, NULL }
};
int
nsldapi_sasl_cvterrno( LDAP *ld, int err, char *msg )
{
int rc = LDAP_LOCAL_ERROR;
switch (err) {
case SASL_OK:
rc = LDAP_SUCCESS;
break;
case SASL_NOMECH:
rc = LDAP_AUTH_UNKNOWN;
break;
case SASL_BADSERV:
rc = LDAP_CONNECT_ERROR;
break;
case SASL_DISABLED:
case SASL_ENCRYPT:
case SASL_EXPIRED:
case SASL_NOUSERPASS:
case SASL_NOVERIFY:
case SASL_PWLOCK:
case SASL_TOOWEAK:
case SASL_UNAVAIL:
case SASL_WEAKPASS:
rc = LDAP_INAPPROPRIATE_AUTH;
break;
case SASL_BADAUTH:
case SASL_NOAUTHZ:
rc = LDAP_INVALID_CREDENTIALS;
break;
case SASL_NOMEM:
rc = LDAP_NO_MEMORY;
break;
case SASL_NOUSER:
rc = LDAP_NO_SUCH_OBJECT;
break;
case SASL_CONTINUE:
case SASL_FAIL:
case SASL_INTERACT:
default:
rc = LDAP_LOCAL_ERROR;
break;
}
LDAP_SET_LDERRNO( ld, rc, NULL, msg );
return( rc );
}
#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
/*
* Get available SASL Mechanisms supported by the server
*/
static int
nsldapi_get_sasl_mechs ( LDAP *ld, char **pmech )
{
char *attr[] = { "supportedSASLMechanisms", NULL };
char **values, **v, *mech, *m;
LDAPMessage *res, *e;
struct timeval timeout;
int slen, rc;
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
return( LDAP_PARAM_ERROR );
}
timeout.tv_sec = SEARCH_TIMEOUT_SECS;
timeout.tv_usec = 0;
rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE,
"objectclass=*", attr, 0, &timeout, &res );
if ( rc != LDAP_SUCCESS ) {
return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
}
e = ldap_first_entry( ld, res );
if ( e == NULL ) {
ldap_msgfree( res );
if ( ld->ld_errno == LDAP_SUCCESS ) {
LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_OBJECT, NULL, NULL );
}
return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
}
values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
if ( values == NULL ) {
ldap_msgfree( res );
LDAP_SET_LDERRNO( ld, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL );
return( LDAP_NO_SUCH_ATTRIBUTE );
}
slen = 0;
for(v = values; *v != NULL; v++ ) {
slen += strlen(*v) + 1;
}
if ( (mech = NSLDAPI_CALLOC(1, slen)) == NULL) {
ldap_value_free( values );
ldap_msgfree( res );
LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
return( LDAP_NO_MEMORY );
}
m = mech;
for(v = values; *v; v++) {
if (v != values) {
*m++ = ' ';
}
slen = strlen(*v);
strncpy(m, *v, slen);
m += slen;
}
*m = '\0';
ldap_value_free( values );
ldap_msgfree( res );
*pmech = mech;
return( LDAP_SUCCESS );
}
#endif /* LDAP_SASLIO_GET_MECHS_FROM_SERVER */
int
nsldapi_sasl_secprops(
const char *in,
sasl_security_properties_t *secprops )
{
int i;
char **props = NULL;
char *inp;
unsigned sflags = 0;
sasl_ssf_t max_ssf = 0;
sasl_ssf_t min_ssf = 0;
unsigned maxbufsize = 0;
int got_sflags = 0;
int got_max_ssf = 0;
int got_min_ssf = 0;
int got_maxbufsize = 0;
if (in == NULL) {
return LDAP_PARAM_ERROR;
}
inp = nsldapi_strdup(in);
if (inp == NULL) {
return LDAP_PARAM_ERROR;
}
props = ldap_str2charray( inp, "," );
NSLDAPI_FREE( inp );
if( props == NULL || secprops == NULL ) {
return LDAP_PARAM_ERROR;
}
for( i=0; props[i]; i++ ) {
if( strcasecmp(props[i], "none") == 0 ) {
got_sflags++;
} else if( strcasecmp(props[i], "noactive") == 0 ) {
got_sflags++;
sflags |= SASL_SEC_NOACTIVE;
} else if( strcasecmp(props[i], "noanonymous") == 0 ) {
got_sflags++;
sflags |= SASL_SEC_NOANONYMOUS;
} else if( strcasecmp(props[i], "nodict") == 0 ) {
got_sflags++;
sflags |= SASL_SEC_NODICTIONARY;
} else if( strcasecmp(props[i], "noplain") == 0 ) {
got_sflags++;
sflags |= SASL_SEC_NOPLAINTEXT;
} else if( strcasecmp(props[i], "forwardsec") == 0 ) {
got_sflags++;
sflags |= SASL_SEC_FORWARD_SECRECY;
} else if( strcasecmp(props[i], "passcred") == 0 ) {
got_sflags++;
sflags |= SASL_SEC_PASS_CREDENTIALS;
} else if( strncasecmp(props[i],
"minssf=", sizeof("minssf")) == 0 ) {
if( isdigit( props[i][sizeof("minssf")] ) ) {
got_min_ssf++;
min_ssf = atoi( &props[i][sizeof("minssf")] );
} else {
return LDAP_NOT_SUPPORTED;
}
} else if( strncasecmp(props[i],
"maxssf=", sizeof("maxssf")) == 0 ) {
if( isdigit( props[i][sizeof("maxssf")] ) ) {
got_max_ssf++;
max_ssf = atoi( &props[i][sizeof("maxssf")] );
} else {
return LDAP_NOT_SUPPORTED;
}
} else if( strncasecmp(props[i],
"maxbufsize=", sizeof("maxbufsize")) == 0 ) {
if( isdigit( props[i][sizeof("maxbufsize")] ) ) {
got_maxbufsize++;
maxbufsize = atoi( &props[i][sizeof("maxbufsize")] );
if( maxbufsize &&
(( maxbufsize < SASL_MIN_BUFF_SIZE )
|| (maxbufsize > SASL_MAX_BUFF_SIZE ))) {
return( LDAP_PARAM_ERROR );
}
} else {
return( LDAP_NOT_SUPPORTED );
}
} else {
return( LDAP_NOT_SUPPORTED );
}
}
if(got_sflags) {
secprops->security_flags = sflags;
}
if(got_min_ssf) {
secprops->min_ssf = min_ssf;
}
if(got_max_ssf) {
secprops->max_ssf = max_ssf;
}
if(got_maxbufsize) {
secprops->maxbufsize = maxbufsize;
}
ldap_charray_free( props );
return( LDAP_SUCCESS );
}
#endif /* LDAP_SASLIO_HOOKS */
static int
nsldapi_sasl_bind_s(
LDAP *ld,
const char *dn,
const char *mechanism,
const struct berval *cred,
LDAPControl **serverctrls,
LDAPControl **clientctrls,
struct berval **servercredp,
LDAPControl ***responsectrls
)
{
int err, msgid;
LDAPMessage *result;
LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_sasl_bind_s\n", 0, 0, 0 );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
return( LDAP_PARAM_ERROR );
}
if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
return( LDAP_NOT_SUPPORTED );
}
if ( ( err = ldap_sasl_bind( ld, dn, mechanism, cred, serverctrls,
clientctrls, &msgid )) != LDAP_SUCCESS )
return( err );
if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result ) == -1 )
return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
/* Get the controls sent by the server if requested */
if ( responsectrls ) {
if ( ( err = ldap_parse_result( ld, result, &err, NULL, NULL,
NULL, responsectrls, 0 )) != LDAP_SUCCESS )
return( err );
}
err = ldap_parse_sasl_bind_result( ld, result, servercredp, 0 );
if (err != LDAP_SUCCESS && err != LDAP_SASL_BIND_IN_PROGRESS) {
ldap_msgfree( result );
return( err );
}
return( ldap_result2error( ld, result, 1 ) );
}
#ifdef LDAP_SASLIO_HOOKS
static int
nsldapi_sasl_do_bind( LDAP *ld, const char *dn,
const char *mechs, unsigned flags,
LDAP_SASL_INTERACT_PROC *callback, void *defaults,
LDAPControl **sctrl, LDAPControl **cctrl, LDAPControl ***rctrl )
{
sasl_interact_t *prompts = NULL;
sasl_conn_t *ctx = NULL;
sasl_ssf_t *ssf = NULL;
const char *mech = NULL;
int saslrc, rc;
struct berval ccred;
unsigned credlen;
int stepnum = 1;
char *sasl_username = NULL;
if (rctrl) {
/* init to NULL so we can call ldap_controls_free below */
*rctrl = NULL;
}
if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) {
LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
return( LDAP_NOT_SUPPORTED );
}
/* shouldn't happen */
if (callback == NULL) {
return( LDAP_LOCAL_ERROR );
}
if ( (rc = nsldapi_sasl_open(ld, NULL, &ctx, 0)) != LDAP_SUCCESS ) {
return( rc );
}
ccred.bv_val = NULL;
ccred.bv_len = 0;
LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n",
(mechs ? mechs : ""), 0, 0 );
do {
saslrc = sasl_client_start( ctx,
mechs,
&prompts,
(const char **)&ccred.bv_val,
&credlen,
&mech );
LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of client start for SASL/%s authentication\n",
stepnum, (mech ? mech : ""), 0 );
stepnum++;
if( saslrc == SASL_INTERACT &&
(callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) {
break;
}
} while ( saslrc == SASL_INTERACT );
ccred.bv_len = credlen;
if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
}
stepnum = 1;
do {
struct berval *scred;
int clientstepnum = 1;
scred = NULL;
if (rctrl) {
/* if we're looping again, we need to free any controls set
during the previous loop */
/* NOTE that this assumes we only care about the controls
returned by the last call to nsldapi_sasl_bind_s - if
we care about _all_ controls, we will have to figure out
some way to append them each loop go round */
ldap_controls_free(*rctrl);
*rctrl = NULL;
}
LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of bind for SASL/%s authentication\n",
stepnum, (mech ? mech : ""), 0 );
stepnum++;
/* notify server of a sasl bind step */
rc = nsldapi_sasl_bind_s(ld, dn, mech, &ccred,
sctrl, cctrl, &scred, rctrl);
if ( ccred.bv_val != NULL ) {
ccred.bv_val = NULL;
}
if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) {
ber_bvfree( scred );
return( rc );
}
if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) {
/* we're done, no need to step */
if( scred ) {
if ( scred->bv_len == 0 ) { /* MS AD sends back empty screds */
LDAPDebug(LDAP_DEBUG_ANY,
"SASL BIND complete - ignoring empty credential response\n",
0, 0, 0);
ber_bvfree( scred );
} else {
/* but server provided us with data! */
LDAPDebug(LDAP_DEBUG_TRACE,
"SASL BIND complete but invalid because server responded with credentials - length [%u]\n",
scred->bv_len, 0, 0);
ber_bvfree( scred );
LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR,
NULL, "Error during SASL handshake - invalid server credential response" );
return( LDAP_LOCAL_ERROR );
}
}
break;
}
/* perform the next step of the sasl bind */
do {
LDAPDebug(LDAP_DEBUG_TRACE, "Doing client step %d of bind step %d for SASL/%s authentication\n",
clientstepnum, stepnum, (mech ? mech : "") );
clientstepnum++;
saslrc = sasl_client_step( ctx,
(scred == NULL) ? NULL : scred->bv_val,
(scred == NULL) ? 0 : scred->bv_len,
&prompts,
(const char **)&ccred.bv_val,
&credlen );
if( saslrc == SASL_INTERACT &&
(callback)(ld, flags, defaults, prompts)
!= LDAP_SUCCESS ) {
break;
}
} while ( saslrc == SASL_INTERACT );
ccred.bv_len = credlen;
ber_bvfree( scred );
if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) {
return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
}
} while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
if ( rc != LDAP_SUCCESS ) {
return( rc );
}
if ( saslrc != SASL_OK ) {
return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) );
}
saslrc = sasl_getprop( ctx, SASL_USERNAME, (const void **) &sasl_username );
if ( (saslrc == SASL_OK) && sasl_username ) {
LDAPDebug(LDAP_DEBUG_TRACE, "SASL identity: %s\n", sasl_username, 0, 0);
}
saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
if( saslrc == SASL_OK ) {
if( ssf && *ssf ) {
LDAPDebug(LDAP_DEBUG_TRACE,
"SASL install encryption, for SSF: %lu\n",
(unsigned long) *ssf, 0, 0 );
nsldapi_sasl_install( ld, NULL );
}
}
return( rc );
}
#endif /* LDAP_SASLIO_HOOKS */
/*
* ldap_sasl_bind - authenticate to the ldap server. The dn, mechanism,
* and credentials of the entry to which to bind are supplied. An LDAP
* error code is returned and if LDAP_SUCCESS is returned *msgidp is set
* to the id of the request initiated.
*
* Example:
* struct berval creds;
* LDAPControl **ctrls;
* int err, msgid;
* ... fill in creds with credentials ...
* ... fill in ctrls with server controls ...
* err = ldap_sasl_bind( ld, "cn=manager, o=university of michigan, c=us",
* "mechanismname", &creds, ctrls, NULL, &msgid );
*/
int
LDAP_CALL
ldap_sasl_bind(
LDAP *ld,
const char *dn,
const char *mechanism,
const struct berval *cred,
LDAPControl **serverctrls,
LDAPControl **clientctrls,
int *msgidp
)
{
BerElement *ber;
int rc, simple, msgid, ldapversion;
/*
* The ldapv3 bind request looks like this:
* BindRequest ::= SEQUENCE {
* version INTEGER,
* name DistinguishedName, -- who
* authentication CHOICE {
* simple [0] OCTET STRING, -- passwd
* sasl [3] SaslCredentials -- v3 only
* }
* }
* SaslCredentials ::= SEQUENCE {
* mechanism LDAPString,
* credentials OCTET STRING
* }
* all wrapped up in an LDAPMessage sequence.
*/
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n", 0, 0, 0 );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
return( LDAP_PARAM_ERROR );
}
if ( msgidp == NULL ) {
LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
return( LDAP_PARAM_ERROR );
}
if ( ( ld->ld_options & LDAP_BITOPT_RECONNECT ) != 0 ) {
nsldapi_handle_reconnect( ld );
}
simple = ( mechanism == LDAP_SASL_SIMPLE );
ldapversion = NSLDAPI_LDAP_VERSION( ld );
/* only ldapv3 or higher can do sasl binds */
if ( !simple && ldapversion < LDAP_VERSION3 ) {
LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
return( LDAP_NOT_SUPPORTED );
}
LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
msgid = ++ld->ld_msgid;
LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
if ( dn == NULL )
dn = "";
if ( ld->ld_cache_on && ld->ld_cache_bind != NULL ) {
LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
if ( (rc = (ld->ld_cache_bind)( ld, msgid, LDAP_REQ_BIND, dn,
cred, LDAP_AUTH_SASL )) != 0 ) {
*msgidp = rc;
LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
return( LDAP_SUCCESS );
}
LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
}
/* create a message to send */
if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
!= LDAP_SUCCESS ) {
return( rc );
}
/* fill it in */
if ( simple ) { /* simple bind; works in LDAPv2 or v3 */
struct berval tmpcred;
if ( cred == NULL ) {
tmpcred.bv_val = "";
tmpcred.bv_len = 0;
cred = &tmpcred;
}
rc = ber_printf( ber, "{it{isto}", msgid, LDAP_REQ_BIND,
ldapversion, dn, LDAP_AUTH_SIMPLE, cred->bv_val,
cred->bv_len );
} else { /* SASL bind; requires LDAPv3 or better */
if ( cred == NULL || cred->bv_val == NULL || cred->bv_len == 0) {
rc = ber_printf( ber, "{it{ist{s}}", msgid,
LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL,
mechanism );
} else {
rc = ber_printf( ber, "{it{ist{so}}", msgid,
LDAP_REQ_BIND, ldapversion, dn, LDAP_AUTH_SASL,
mechanism, cred->bv_val,
cred->bv_len );
}
}
if ( rc == -1 ) {
LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
ber_free( ber, 1 );
return( LDAP_ENCODING_ERROR );
}
if ( (rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
!= LDAP_SUCCESS ) {
ber_free( ber, 1 );
return( rc );
}
/* send the message */
rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_BIND,
(char *)dn, ber );
*msgidp = rc;
return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
}
/*
* ldap_sasl_bind_s - bind to the ldap server using sasl authentication
* The dn, mechanism, and credentials of the entry to which to bind are
* supplied. LDAP_SUCCESS is returned upon success, the ldap error code
* otherwise.
*
* Example:
* struct berval creds;
* ... fill in creds with credentials ...
* ldap_sasl_bind_s( ld, "cn=manager, o=university of michigan, c=us",
* "mechanismname", &creds )
*/
int
LDAP_CALL
ldap_sasl_bind_s(
LDAP *ld,
const char *dn,
const char *mechanism,
const struct berval *cred,
LDAPControl **serverctrls,
LDAPControl **clientctrls,
struct berval **servercredp
)
{
return ( nsldapi_sasl_bind_s( ld, dn, mechanism, cred,
serverctrls, clientctrls, servercredp, NULL ) );
}
#ifdef LDAP_SASLIO_HOOKS
/*
* SASL Authentication Interface: ldap_sasl_interactive_bind_s
*
* This routine takes a DN, SASL mech list, and a SASL callback
* and performs the necessary sequencing to complete a SASL bind
* to the LDAP connection ld. The user provided callback can
* use an optionally provided set of default values to complete
* any necessary interactions.
*
* Currently imposes the following restrictions:
* A mech list must be provided
* LDAP_SASL_INTERACTIVE mode requires a callback
*/
int
LDAP_CALL
ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
const char *saslMechanism,
LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
LDAP_SASL_INTERACT_PROC *callback, void *defaults )
{
return ldap_sasl_interactive_bind_ext_s( ld, dn,
saslMechanism, sctrl, cctrl, flags, callback,
defaults, NULL );
}
/*
* ldap_sasl_interactive_bind_ext_s
*
* This function extends ldap_sasl_interactive_bind_s by allowing
* controls received from the server to be returned as rctrl. The
* caller must pass in a valid LDAPControl** pointer and free the
* array of controls when finished with them e.g.
* LDAPControl **retctrls = NULL;
* ...
* ldap_sasl_interactive_bind_ext_s(ld, ...., &retctrls);
* ...
* ldap_controls_free(retctrls);
* Only the controls from the server during the last bind step are returned -
* intermediate controls (if any, usually not) are discarded.
*/
int
LDAP_CALL
ldap_sasl_interactive_bind_ext_s( LDAP *ld, const char *dn,
const char *saslMechanism,
LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
LDAP_SASL_INTERACT_PROC *callback, void *defaults, LDAPControl ***rctrl )
{
#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
char *smechs;
#endif
int rc;
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_sasl_interactive_bind_s\n", 0, 0, 0 );
if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
return( LDAP_PARAM_ERROR );
}
if ((flags == LDAP_SASL_INTERACTIVE) && (callback == NULL)) {
return( LDAP_PARAM_ERROR );
}
LDAP_MUTEX_LOCK(ld, LDAP_SASL_LOCK );
if( saslMechanism == NULL || *saslMechanism == '\0' ) {
#ifdef LDAP_SASLIO_GET_MECHS_FROM_SERVER
rc = nsldapi_get_sasl_mechs( ld, &smechs );
if( rc != LDAP_SUCCESS ) {
LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
return( rc );
}
saslMechanism = smechs;
#else
LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
return( LDAP_PARAM_ERROR );
#endif /* LDAP_SASLIO_GET_MECHS_FROM_SERVER */
}
rc = nsldapi_sasl_do_bind( ld, dn, saslMechanism,
flags, callback, defaults, sctrl, cctrl, rctrl);
LDAP_MUTEX_UNLOCK(ld, LDAP_SASL_LOCK );
return( rc );
}
#else /* LDAP_SASLIO_HOOKS */
/* stubs for platforms that do not support SASL */
int
LDAP_CALL
ldap_sasl_interactive_bind_s( LDAP *ld, const char *dn,
const char *saslMechanism,
LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
LDAP_SASL_INTERACT_PROC *callback, void *defaults )
{
return LDAP_SUCCESS;
}
int
LDAP_CALL
ldap_sasl_interactive_bind_ext_s( LDAP *ld, const char *dn,
const char *saslMechanism,
LDAPControl **sctrl, LDAPControl **cctrl, unsigned flags,
LDAP_SASL_INTERACT_PROC *callback, void *defaults, LDAPControl ***rctrl )
{
return LDAP_SUCCESS;
}
#endif /* LDAP_SASLIO_HOOKS */
/* returns an LDAP error code that indicates if parse succeeded or not */
int
LDAP_CALL
ldap_parse_sasl_bind_result(
LDAP *ld,
LDAPMessage *res,
struct berval **servercredp,
int freeit
)
{
BerElement ber;
int rc, err;
ber_int_t along;
ber_len_t len;
char *m, *e;
LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n", 0, 0, 0 );
/*
* the ldapv3 SASL bind response looks like this:
*
* BindResponse ::= [APPLICATION 1] SEQUENCE {
* COMPONENTS OF LDAPResult,
* serverSaslCreds [7] OCTET STRING OPTIONAL
* }
*
* all wrapped up in an LDAPMessage sequence.
*/
if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
!NSLDAPI_VALID_LDAPMESSAGE_BINDRESULT_POINTER( res )) {
return( LDAP_PARAM_ERROR );
}
/* only ldapv3 or higher can do sasl binds */
if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
return( LDAP_NOT_SUPPORTED );
}
if ( servercredp != NULL ) {
*servercredp = NULL;
}
ber = *(res->lm_ber); /* struct copy */
/* skip past message id, matched dn, error message ... */
rc = ber_scanf( &ber, "{iaa}", &along, &m, &e );
if ( rc != LBER_ERROR &&
ber_peek_tag( &ber, &len ) == LDAP_TAG_SASL_RES_CREDS ) {
rc = ber_get_stringal( &ber, servercredp );
}
if ( freeit ) {
ldap_msgfree( res );
}
if ( rc == LBER_ERROR ) {
err = LDAP_DECODING_ERROR;
} else {
err = (int) along;
}
LDAP_SET_LDERRNO( ld, err, m, e );
/* this is a little kludge for the 3.0 Barracuda/hammerhead relese */
/* the docs state that the return is either LDAP_DECODING_ERROR */
/* or LDAP_SUCCESS. Here we match the docs... it's cleaner in 3.1 */
if ( LDAP_DECODING_ERROR == err ) {
return (LDAP_DECODING_ERROR);
} else {
return( LDAP_SUCCESS );
}
}