1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  *
3*0Sstevel@tonic-gate  * Copyright %G% Sun Microsystems, Inc.
4*0Sstevel@tonic-gate  * All Rights Reserved
5*0Sstevel@tonic-gate  *
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * Comments:
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  */
10*0Sstevel@tonic-gate 
11*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
12*0Sstevel@tonic-gate 
13*0Sstevel@tonic-gate #include <stdio.h>
14*0Sstevel@tonic-gate #include <string.h>
15*0Sstevel@tonic-gate 
16*0Sstevel@tonic-gate #include "lber.h"
17*0Sstevel@tonic-gate #include "ldap.h"
18*0Sstevel@tonic-gate #include "ldap-private.h"
19*0Sstevel@tonic-gate #include "ldap-int.h"
20*0Sstevel@tonic-gate #include "sec.h"
21*0Sstevel@tonic-gate #include <strings.h>
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate BerElement * ldap_build_sasl_bind_req( LDAP *ld, char *dn, char *mechanism, struct berval *creds, LDAPControl ** serverctrls)
24*0Sstevel@tonic-gate {
25*0Sstevel@tonic-gate 	BerElement *ber = NULL;
26*0Sstevel@tonic-gate 	int err;
27*0Sstevel@tonic-gate 
28*0Sstevel@tonic-gate 	/* Create a Bind Request for SASL authentication.
29*0Sstevel@tonic-gate 	 * It look like this :
30*0Sstevel@tonic-gate 	 * BindRequest := [APPLICATION 0] SEQUENCE {
31*0Sstevel@tonic-gate 	 *		version		INTEGER,
32*0Sstevel@tonic-gate 	 *		name		LDAPDN,
33*0Sstevel@tonic-gate 	 *		authentication	CHOICE {
34*0Sstevel@tonic-gate 	 *			sasl		[3] SEQUENCE {
35*0Sstevel@tonic-gate 	 *				mechanism	LDAPString,
36*0Sstevel@tonic-gate 	 *				credential	OCTET STRING OPTIONAL
37*0Sstevel@tonic-gate 	 * 			}
38*0Sstevel@tonic-gate 	 *		}
39*0Sstevel@tonic-gate 	 *	}
40*0Sstevel@tonic-gate 	 * all wrapped up in an LDAPMessage sequence.
41*0Sstevel@tonic-gate 	 */
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate 	if (dn == NULL || *dn == '\0'){
44*0Sstevel@tonic-gate 		ld->ld_errno = LDAP_PARAM_ERROR;
45*0Sstevel@tonic-gate 		return (NULLBER);
46*0Sstevel@tonic-gate 	}
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate 	if ( (ber = alloc_ber_with_options( ld )) == NULLBER ) {
50*0Sstevel@tonic-gate 		return (NULLBER);
51*0Sstevel@tonic-gate 	}
52*0Sstevel@tonic-gate 	if ( ber_printf( ber, "{it{ist{s", ++ld->ld_msgid, LDAP_REQ_BIND, ld->ld_version, dn, LDAP_AUTH_SASL, mechanism) == -1){
53*0Sstevel@tonic-gate 		ld->ld_errno = LDAP_ENCODING_ERROR;
54*0Sstevel@tonic-gate 		ber_free(ber, 1);
55*0Sstevel@tonic-gate 		return (NULLBER);
56*0Sstevel@tonic-gate 	}
57*0Sstevel@tonic-gate 	if (creds != NULL && creds->bv_val != NULL) {
58*0Sstevel@tonic-gate 		if (ber_printf(ber, "o", creds->bv_val, creds->bv_len) == -1){
59*0Sstevel@tonic-gate 			ld->ld_errno = LDAP_ENCODING_ERROR;
60*0Sstevel@tonic-gate 			ber_free(ber, 1);
61*0Sstevel@tonic-gate 			return (NULLBER);
62*0Sstevel@tonic-gate 		}
63*0Sstevel@tonic-gate 	}
64*0Sstevel@tonic-gate 	if (ber_printf(ber, "}}") == -1){
65*0Sstevel@tonic-gate 		ld->ld_errno = LDAP_ENCODING_ERROR;
66*0Sstevel@tonic-gate 		ber_free( ber, 1 );
67*0Sstevel@tonic-gate 		return( NULLBER );
68*0Sstevel@tonic-gate 	}
69*0Sstevel@tonic-gate 	/* LDAPv3 */
70*0Sstevel@tonic-gate 	/* Code controls if any */
71*0Sstevel@tonic-gate 	if (serverctrls && serverctrls[0]) {
72*0Sstevel@tonic-gate 		if (ldap_controls_code(ber, serverctrls) != LDAP_SUCCESS){
73*0Sstevel@tonic-gate 			ld->ld_errno = LDAP_ENCODING_ERROR;
74*0Sstevel@tonic-gate 			ber_free( ber, 1 );
75*0Sstevel@tonic-gate 			return( NULLBER );
76*0Sstevel@tonic-gate 		}
77*0Sstevel@tonic-gate 	} else if (ld->ld_srvctrls && ld->ld_srvctrls[0]) {
78*0Sstevel@tonic-gate 		/* Otherwise, is there any global server ctrls ? */
79*0Sstevel@tonic-gate 		if (ldap_controls_code(ber, ld->ld_srvctrls) != LDAP_SUCCESS){
80*0Sstevel@tonic-gate 			ld->ld_errno = LDAP_ENCODING_ERROR;
81*0Sstevel@tonic-gate 			ber_free( ber, 1 );
82*0Sstevel@tonic-gate 			return( NULLBER );
83*0Sstevel@tonic-gate 		}
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	if ( ber_printf( ber, "}" ) == -1 ) {
87*0Sstevel@tonic-gate 		ld->ld_errno = LDAP_ENCODING_ERROR;
88*0Sstevel@tonic-gate 		ber_free( ber, 1 );
89*0Sstevel@tonic-gate 		return( NULLBER );
90*0Sstevel@tonic-gate 	}
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	return (ber);
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate /*
96*0Sstevel@tonic-gate  * ldap_sasl_bind - bind to the ldap server (and X.500).
97*0Sstevel@tonic-gate  * dn, mechanism, cred, serverctrls, and clientctrls are supplied.
98*0Sstevel@tonic-gate  * the message id of the request is returned in msgid
99*0Sstevel@tonic-gate  * Returns LDAP_SUCCESS or an error code.
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate int ldap_sasl_bind(
103*0Sstevel@tonic-gate 	LDAP *ld,
104*0Sstevel@tonic-gate 	char *dn,
105*0Sstevel@tonic-gate 	char *mechanism,
106*0Sstevel@tonic-gate 	struct berval *cred,
107*0Sstevel@tonic-gate 	LDAPControl **serverctrls,
108*0Sstevel@tonic-gate 	LDAPControl **clientctrls,
109*0Sstevel@tonic-gate 	int *msgidp)
110*0Sstevel@tonic-gate {
111*0Sstevel@tonic-gate 	int theErr = LDAP_SUCCESS;
112*0Sstevel@tonic-gate 	int rv;
113*0Sstevel@tonic-gate 	BerElement *ber = NULL;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0);
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate #ifdef _REENTRANT
118*0Sstevel@tonic-gate 	LOCK_LDAP(ld);
119*0Sstevel@tonic-gate #endif
120*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_SIMPLE) == 0){
121*0Sstevel@tonic-gate 		/* Simple bind */
122*0Sstevel@tonic-gate 		if ( (ber = ldap_build_simple_bind_req(ld, dn, cred->bv_val, serverctrls)) == NULLBER){
123*0Sstevel@tonic-gate 			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
124*0Sstevel@tonic-gate #ifdef _REENTRANT
125*0Sstevel@tonic-gate 			UNLOCK_LDAP(ld);
126*0Sstevel@tonic-gate #endif
127*0Sstevel@tonic-gate 			return (theErr);
128*0Sstevel@tonic-gate 		}
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_CRAM_MD5) == 0){
132*0Sstevel@tonic-gate 		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_CRAM_MD5, cred, serverctrls)) == NULLBER) {
133*0Sstevel@tonic-gate 			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
134*0Sstevel@tonic-gate #ifdef _REENTRANT
135*0Sstevel@tonic-gate 			UNLOCK_LDAP(ld);
136*0Sstevel@tonic-gate #endif
137*0Sstevel@tonic-gate 			return (theErr);
138*0Sstevel@tonic-gate 		}
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_EXTERNAL) == 0){
142*0Sstevel@tonic-gate 		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_EXTERNAL, cred, serverctrls)) == NULLBER) {
143*0Sstevel@tonic-gate 			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
144*0Sstevel@tonic-gate #ifdef _REENTRANT
145*0Sstevel@tonic-gate 			UNLOCK_LDAP(ld);
146*0Sstevel@tonic-gate #endif
147*0Sstevel@tonic-gate 			return (theErr);
148*0Sstevel@tonic-gate 		}
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_X511_PROTECTED) == 0){
152*0Sstevel@tonic-gate #ifdef _REENTRANT
153*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
154*0Sstevel@tonic-gate #endif
155*0Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
156*0Sstevel@tonic-gate /*
157*0Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
158*0Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
159*0Sstevel@tonic-gate  *#ifdef _REENTRANT
160*0Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
161*0Sstevel@tonic-gate  *#endif
162*0Sstevel@tonic-gate  *			return (theErr);
163*0Sstevel@tonic-gate  *		}
164*0Sstevel@tonic-gate  */
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_X511_STRONG) == 0){
167*0Sstevel@tonic-gate #ifdef _REENTRANT
168*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
169*0Sstevel@tonic-gate #endif
170*0Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
171*0Sstevel@tonic-gate /*
172*0Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
173*0Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
174*0Sstevel@tonic-gate  *#ifdef _REENTRANT
175*0Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
176*0Sstevel@tonic-gate  *#endif
177*0Sstevel@tonic-gate  *			return (theErr);
178*0Sstevel@tonic-gate  *		}
179*0Sstevel@tonic-gate  */
180*0Sstevel@tonic-gate 	}
181*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_KERBEROS_V4) == 0){
182*0Sstevel@tonic-gate #ifdef _REENTRANT
183*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
184*0Sstevel@tonic-gate #endif
185*0Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
186*0Sstevel@tonic-gate /*
187*0Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
188*0Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
189*0Sstevel@tonic-gate  *#ifdef _REENTRANT
190*0Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
191*0Sstevel@tonic-gate  *#endif
192*0Sstevel@tonic-gate  *			return (theErr);
193*0Sstevel@tonic-gate  *		}
194*0Sstevel@tonic-gate  */
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_GSSAPI) == 0){
197*0Sstevel@tonic-gate #ifdef _REENTRANT
198*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
199*0Sstevel@tonic-gate #endif
200*0Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
201*0Sstevel@tonic-gate /*
202*0Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
203*0Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
204*0Sstevel@tonic-gate  *#ifdef _REENTRANT
205*0Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
206*0Sstevel@tonic-gate  *#endif
207*0Sstevel@tonic-gate  *			return (theErr);
208*0Sstevel@tonic-gate  *		}
209*0Sstevel@tonic-gate  */
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate 	if (strcasecmp(mechanism, LDAP_SASL_SKEY) == 0){
212*0Sstevel@tonic-gate #ifdef _REENTRANT
213*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
214*0Sstevel@tonic-gate #endif
215*0Sstevel@tonic-gate 		return (LDAP_NOT_SUPPORTED);
216*0Sstevel@tonic-gate /*
217*0Sstevel@tonic-gate  *		if (( ber = ldap_build_sasl_bind_req(ld, dn, LDAP_SASL_X511_PROTECTED, cred, serverctrls)) == NULLBER) {
218*0Sstevel@tonic-gate  *			ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &theErr);
219*0Sstevel@tonic-gate  *#ifdef _REENTRANT
220*0Sstevel@tonic-gate  *			UNLOCK_LDAP(ld);
221*0Sstevel@tonic-gate  *#endif
222*0Sstevel@tonic-gate  *			return (theErr);
223*0Sstevel@tonic-gate  *		}
224*0Sstevel@tonic-gate  */
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 	if (ber == NULL){
227*0Sstevel@tonic-gate #ifdef _REENTRANT
228*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
229*0Sstevel@tonic-gate #endif
230*0Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
231*0Sstevel@tonic-gate 	}
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate #ifndef NO_CACHE
234*0Sstevel@tonic-gate 	if ( ld->ld_cache != NULL ) {
235*0Sstevel@tonic-gate 		ldap_flush_cache( ld );
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate #endif /* !NO_CACHE */
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	/* send the message */
240*0Sstevel@tonic-gate 	rv = send_initial_request( ld, LDAP_REQ_BIND, dn, ber );
241*0Sstevel@tonic-gate 	if (rv == -1){
242*0Sstevel@tonic-gate 		rv = ld->ld_errno;
243*0Sstevel@tonic-gate 		if (rv == LDAP_SUCCESS){
244*0Sstevel@tonic-gate 			rv = LDAP_OTHER;
245*0Sstevel@tonic-gate 		}
246*0Sstevel@tonic-gate #ifdef _REENTRANT
247*0Sstevel@tonic-gate 		UNLOCK_LDAP(ld);
248*0Sstevel@tonic-gate #endif
249*0Sstevel@tonic-gate 		return (rv);
250*0Sstevel@tonic-gate 	}
251*0Sstevel@tonic-gate 	*msgidp = rv;
252*0Sstevel@tonic-gate #ifdef _REENTRANT
253*0Sstevel@tonic-gate 	UNLOCK_LDAP(ld);
254*0Sstevel@tonic-gate #endif
255*0Sstevel@tonic-gate 	return ( LDAP_SUCCESS );
256*0Sstevel@tonic-gate }
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate /*
259*0Sstevel@tonic-gate  * ldap_sasl_bind_s - bind to the ldap server (and X.500).
260*0Sstevel@tonic-gate  * dn, mechanism, cred, serverctrls, and clientctrls are supplied.
261*0Sstevel@tonic-gate  * the message id of the request is returned in msgid
262*0Sstevel@tonic-gate  * Returns LDAP_SUCCESS or an error code.
263*0Sstevel@tonic-gate  */
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate int ldap_sasl_bind_s(
266*0Sstevel@tonic-gate 	LDAP *ld,
267*0Sstevel@tonic-gate 	char *dn,
268*0Sstevel@tonic-gate 	char *mechanism,
269*0Sstevel@tonic-gate 	struct berval *cred,
270*0Sstevel@tonic-gate 	LDAPControl **serverctrls,
271*0Sstevel@tonic-gate 	LDAPControl **clientctrls,
272*0Sstevel@tonic-gate 	struct berval **servercredp)
273*0Sstevel@tonic-gate {
274*0Sstevel@tonic-gate 	int msgid;
275*0Sstevel@tonic-gate 	int retcode;
276*0Sstevel@tonic-gate 	LDAPMessage *res;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	Debug ( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 1288, "ldap_sasl_bind\n"), 0,0,0);
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	if ((retcode = ldap_sasl_bind(ld, dn, mechanism, cred, serverctrls, clientctrls, &msgid)) != LDAP_SUCCESS)
281*0Sstevel@tonic-gate 		return (retcode);
282*0Sstevel@tonic-gate 	if (ldap_result(ld, msgid, 1, (struct timeval *)NULL, &res ) == -1)
283*0Sstevel@tonic-gate 		return (ld->ld_errno );
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	return (ldap_parse_sasl_bind_result(ld, res, servercredp, 1));
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate int ldap_sasl_cram_md5_bind_s(
289*0Sstevel@tonic-gate 	LDAP *ld,
290*0Sstevel@tonic-gate 	char *dn,
291*0Sstevel@tonic-gate 	struct berval *cred,
292*0Sstevel@tonic-gate 	LDAPControl **serverctrls,
293*0Sstevel@tonic-gate 	LDAPControl **clientctrls )
294*0Sstevel@tonic-gate {
295*0Sstevel@tonic-gate 	int res;
296*0Sstevel@tonic-gate 	struct berval *challenge = NULL;
297*0Sstevel@tonic-gate 	struct berval resp;
298*0Sstevel@tonic-gate 	unsigned char digest[16];
299*0Sstevel@tonic-gate 	char *theHDigest;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	if (dn == NULL){
302*0Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
303*0Sstevel@tonic-gate 	}
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	bzero(digest, sizeof (digest));
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	if ((res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, NULL, serverctrls, clientctrls, &challenge))
308*0Sstevel@tonic-gate 		!= LDAP_SASL_BIND_INPROGRESS){
309*0Sstevel@tonic-gate 		return (res);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 	if (challenge == NULL){
312*0Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 	Debug (LDAP_DEBUG_TRACE, "SASL challenge: %s\n", challenge->bv_val, 0, 0);
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	hmac_md5((unsigned char *)challenge->bv_val, challenge->bv_len,
318*0Sstevel@tonic-gate 					 (unsigned char *)cred->bv_val, cred->bv_len,  digest);
319*0Sstevel@tonic-gate 	ber_bvfree(challenge);
320*0Sstevel@tonic-gate 	challenge = NULL;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	theHDigest = hexa_print(digest, 16);
323*0Sstevel@tonic-gate 	if (theHDigest == NULL){
324*0Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
325*0Sstevel@tonic-gate 	}
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	resp.bv_len = (strlen(dn) + 32 + 1);
328*0Sstevel@tonic-gate 	if ((resp.bv_val = (char *)malloc(resp.bv_len+1)) == NULL) {
329*0Sstevel@tonic-gate 		return(LDAP_NO_MEMORY);
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	sprintf(resp.bv_val, "%s %s", dn, theHDigest);
333*0Sstevel@tonic-gate 	free(theHDigest);
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	Debug (LDAP_DEBUG_TRACE, "SASL response: %s\n", resp.bv_val, 0, 0);
336*0Sstevel@tonic-gate 	res = ldap_sasl_bind_s(ld, dn, LDAP_SASL_CRAM_MD5, &resp, serverctrls, clientctrls, &challenge);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	free(resp.bv_val);
339*0Sstevel@tonic-gate 	return (res);
340*0Sstevel@tonic-gate }
341