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