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