OpenSolaris_b135/lib/libldap4/common/saslbind.c

Compare this file to the similar file:
Show the results in this format:

/*
 *
 * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 *
 * Comments:   
 *
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdio.h>
#include <string.h>

#include "lber.h"
#include "ldap.h"
#include "ldap-private.h"
#include "ldap-int.h"
#include "sec.h"
#include <strings.h>

BerElement * ldap_build_sasl_bind_req( LDAP *ld, char *dn, char *mechanism, struct berval *creds, LDAPControl ** serverctrls)
{
	BerElement *ber = NULL;
	int err;
	
	/* Create a Bind Request for SASL authentication.
	 * It look like this :
	 * BindRequest := [APPLICATION 0] SEQUENCE {
	 *		version		INTEGER,
	 *		name		LDAPDN,
	 *		authentication	CHOICE {
	 *			sasl		[3] SEQUENCE {
	 *				mechanism	LDAPString,
	 *				credential	OCTET STRING OPTIONAL
	 * 			}
	 *		}
	 *	}
	 * all wrapped up in an LDAPMessage sequence.
	 */
	
	if (dn == NULL || *dn == '\0'){
		ld->ld_errno = LDAP_PARAM_ERROR;
		return (NULLBER);
	}
	
	
	if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
		return (NULLBER);
	}
	if ( ber_printf( ber, "{it{ist{s", ++ld->ld_msgid, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SASL, mechanism) == -1){
		ld->ld_errno = LDAP_ENCODING_ERROR;
		ber_free(ber, 1);
		return (NULLBER);
	}
	if (creds != NULL && creds->bv_val != NULL) {
		if (ber_printf(ber, "o", creds->bv_val, creds->bv_len) == -1){
			ld->ld_errno = LDAP_ENCODING_ERROR;
			ber_free(ber, 1);
			return (NULLBER);
		}
	}
	if (ber_printf(ber, "}}") == -1){
		ld->ld_errno = LDAP_ENCODING_ERROR;
		ber_free( ber, 1 );
		return( NULLBER );
	}
	/* LDAPv3 */
	/* Code controls if any */
	if (serverctrls && serverctrls[0]) {
		if (ldap_controls_code(ber, serverctrls) != LDAP_SUCCESS){
			ld->ld_errno = LDAP_ENCODING_ERROR;
			ber_free( ber, 1 );
			return( NULLBER );
		}
	} else if (ld->ld_srvctrls && ld->ld_srvctrls[0]) {
		/* Otherwise, is there any global server ctrls ? */
		if (ldap_controls_code(ber, ld->ld_srvctrls) != LDAP_SUCCESS){
			ld->ld_errno = LDAP_ENCODING_ERROR;
			ber_free( ber, 1 );
			return( NULLBER );
		}
	}

	if ( ber_printf( ber, "}" ) == -1 ) {
		ld->ld_errno = LDAP_ENCODING_ERROR;
		ber_free( ber, 1 );
		return( NULLBER );
	}
	
	return (ber);
}

/* 
 * ldap_sasl_bind - bind to the ldap server (and X.500).
 * dn, mechanism, cred, serverctrls, and clientctrls are supplied. 
 * the message id of the request is returned in msgid
 * Returns LDAP_SUCCESS or an error code.
 */

int ldap_sasl_bind(
	LDAP *ld,
	char *dn,
	char *mechanism,
	struct berval *cred,
	LDAPControl **serverctrls,
	LDAPControl **clientctrls,
	int *msgidp)
{
	int theErr = LDAP_SUCCESS;
	int rv;
	BerElement *ber = NULL;
	
	Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0);

#ifdef _REENTRANT
	LOCK_LDAP(ld);
#endif
	if (strcasecmp(mechanism, LDAP_SASL_SIMPLE) == 0){
		/* Simple bind */
		if ( (ber = ldap_build_simple_bind_req(ld, dn, cred->bv_val, serverctrls)) == NULLBER){
			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
#ifdef _REENTRANT
			UNLOCK_LDAP(ld);
#endif	
			return (theErr);
		}
	}

	if (strcasecmp(mechanism, LDAP_SASL_CRAM_MD5) == 0){
		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_CRAM_MD5, cred, serverctrls)) == NULLBER) {
			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
#ifdef _REENTRANT
			UNLOCK_LDAP(ld);
#endif	
			return (theErr);
		}
	}

	if (strcasecmp(mechanism, LDAP_SASL_EXTERNAL) == 0){
		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_EXTERNAL, cred, serverctrls)) == NULLBER) {
			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
#ifdef _REENTRANT
			UNLOCK_LDAP(ld);
#endif	
			return (theErr);
		}
	}

	if (strcasecmp(mechanism, LDAP_SASL_X511_PROTECTED) == 0){
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif	
		return (LDAP_NOT_SUPPORTED);
/* 
 *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
 *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
 *#ifdef _REENTRANT
 *			UNLOCK_LDAP(ld);
 *#endif	
 *			return (theErr);
 *		}
 */		
	}
	if (strcasecmp(mechanism, LDAP_SASL_X511_STRONG) == 0){
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif	
		return (LDAP_NOT_SUPPORTED);
/* 
 *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
 *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
 *#ifdef _REENTRANT
 *			UNLOCK_LDAP(ld);
 *#endif	
 *			return (theErr);
 *		}
 */		
	}
	if (strcasecmp(mechanism, LDAP_SASL_KERBEROS_V4) == 0){
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif	
		return (LDAP_NOT_SUPPORTED);
/* 
 *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
 *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
 *#ifdef _REENTRANT
 *			UNLOCK_LDAP(ld);
 *#endif	
 *			return (theErr);
 *		}
 */		
	}
	if (strcasecmp(mechanism, LDAP_SASL_GSSAPI) == 0){
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif	
		return (LDAP_NOT_SUPPORTED);
/* 
 *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
 *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
 *#ifdef _REENTRANT
 *			UNLOCK_LDAP(ld);
 *#endif	
 *			return (theErr);
 *		}
 */		
	}
	if (strcasecmp(mechanism, LDAP_SASL_SKEY) == 0){
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif	
		return (LDAP_NOT_SUPPORTED);
/* 
 *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
 *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
 *#ifdef _REENTRANT
 *			UNLOCK_LDAP(ld);
 *#endif	
 *			return (theErr);
 *		}
 */		
	}
	if (ber == NULL){
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif	
		return (LDAP_PARAM_ERROR);
	}

#ifndef NO_CACHE
	if ( ld->ld_cache != NULL ) {
		ldap_flush_cache( ld );
	}
#endif /* !NO_CACHE */
	
	/* send the message */
	rv = send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
	if (rv == -1){
		rv = ld->ld_errno;
		if (rv == LDAP_SUCCESS){
			rv = LDAP_OTHER;
		}
#ifdef _REENTRANT
		UNLOCK_LDAP(ld);
#endif
		return (rv);
	}
	*msgidp = rv;
#ifdef _REENTRANT
	UNLOCK_LDAP(ld);
#endif
	return ( LDAP_SUCCESS );
}

/* 
 * ldap_sasl_bind_s - bind to the ldap server (and X.500).
 * dn, mechanism, cred, serverctrls, and clientctrls are supplied. 
 * the message id of the request is returned in msgid
 * Returns LDAP_SUCCESS or an error code.
 */

int ldap_sasl_bind_s(	
	LDAP *ld,
	char *dn,
	char *mechanism,
	struct berval *cred,
	LDAPControl **serverctrls,
	LDAPControl **clientctrls,
	struct berval **servercredp)
{
	int msgid;
	int retcode;
	LDAPMessage *res;
	
	Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0);

	if ((retcode = ldap_sasl_bind(ld, dn, mechanism, cred, serverctrls, clientctrls, &msgid)) != LDAP_SUCCESS)
		return (retcode);
	if (ldap_result(ld, msgid, 1, (struct timeval *)NULL, &res ) == -1)
		return (ld->ld_errno );

	return (ldap_parse_sasl_bind_result(ld, res, servercredp, 1));
}

int ldap_sasl_cram_md5_bind_s(
	LDAP *ld,
	char *dn,
	struct berval *cred,
	LDAPControl **serverctrls,
	LDAPControl **clientctrls ) 
{
	int res;
	struct berval *challenge = NULL;
	struct berval resp;
	unsigned char digest[16];
	char *theHDigest;
	
	if (dn == NULL){
		return (LDAP_PARAM_ERROR);
	}

	bzero(digest, sizeof (digest));
	
	if ((res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, NULL, serverctrls, clientctrls, &challenge))
		!= LDAP_SASL_BIND_INPROGRESS){
		return (res);
	}
	if (challenge == NULL){
		return (LDAP_PARAM_ERROR);
	}
	
	Debug (LDAP_DEBUG_TRACE, "SASL challenge: %s\n", challenge->bv_val, 0, 0);
	
	hmac_md5((unsigned char *)challenge->bv_val, challenge->bv_len, 
					 (unsigned char *)cred->bv_val, cred->bv_len,  digest);
	ber_bvfree(challenge);
	challenge = NULL;
	
	theHDigest = hexa_print(digest, 16);
	if (theHDigest == NULL){
		return (LDAP_NO_MEMORY);
	}

	resp.bv_len = (strlen(dn) + 32 + 1);
	if ((resp.bv_val = (char *)malloc(resp.bv_len+1)) == NULL) {
		return(LDAP_NO_MEMORY);
	}
	
	sprintf(resp.bv_val, "%s %s", dn, theHDigest);
	free(theHDigest);

	Debug (LDAP_DEBUG_TRACE, "SASL response: %s\n", resp.bv_val, 0, 0);
	res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, &resp, serverctrls, clientctrls, &challenge);

	free(resp.bv_val);
	return (res);
}