/* ***** 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 ); } }