source: vendor/3.6.0/source3/libads/sasl.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 33.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "includes.h"
21#include "../libcli/auth/spnego.h"
22#include "../libcli/auth/ntlmssp.h"
23#include "ads.h"
24#include "smb_krb5.h"
25
26#ifdef HAVE_LDAP
27
28static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
29{
30 struct ntlmssp_state *ntlmssp_state =
31 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
32 ADS_STATUS status;
33 NTSTATUS nt_status;
34 DATA_BLOB sig;
35 TALLOC_CTX *frame;
36 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
37
38 frame = talloc_stackframe();
39 /* copy the data to the right location */
40 memcpy(dptr, buf, len);
41
42 /* create the signature and may encrypt the data */
43 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
44 nt_status = ntlmssp_seal_packet(ntlmssp_state,
45 frame,
46 dptr, len,
47 dptr, len,
48 &sig);
49 } else {
50 nt_status = ntlmssp_sign_packet(ntlmssp_state,
51 frame,
52 dptr, len,
53 dptr, len,
54 &sig);
55 }
56 status = ADS_ERROR_NT(nt_status);
57 if (!ADS_ERR_OK(status)) return status;
58
59 /* copy the signature to the right location */
60 memcpy(ads->ldap.out.buf + 4,
61 sig.data, NTLMSSP_SIG_SIZE);
62
63 TALLOC_FREE(frame);
64
65 /* set how many bytes must be written to the underlying socket */
66 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
67
68 return ADS_SUCCESS;
69}
70
71static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
72{
73 struct ntlmssp_state *ntlmssp_state =
74 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
75 ADS_STATUS status;
76 NTSTATUS nt_status;
77 DATA_BLOB sig;
78 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
79 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
80
81 /* wrap the signature into a DATA_BLOB */
82 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
83
84 /* verify the signature and maybe decrypt the data */
85 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
86 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
87 dptr, dlen,
88 dptr, dlen,
89 &sig);
90 } else {
91 nt_status = ntlmssp_check_packet(ntlmssp_state,
92 dptr, dlen,
93 dptr, dlen,
94 &sig);
95 }
96 status = ADS_ERROR_NT(nt_status);
97 if (!ADS_ERR_OK(status)) return status;
98
99 /* set the amount of bytes for the upper layer and set the ofs to the data */
100 ads->ldap.in.left = dlen;
101 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
102
103 return ADS_SUCCESS;
104}
105
106static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
107{
108 struct ntlmssp_state *ntlmssp_state =
109 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
110
111 TALLOC_FREE(ntlmssp_state);
112
113 ads->ldap.wrap_ops = NULL;
114 ads->ldap.wrap_private_data = NULL;
115}
116
117static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
118 .name = "ntlmssp",
119 .wrap = ads_sasl_ntlmssp_wrap,
120 .unwrap = ads_sasl_ntlmssp_unwrap,
121 .disconnect = ads_sasl_ntlmssp_disconnect
122};
123
124/*
125 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
126 we fit on one socket??)
127*/
128static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
129{
130 DATA_BLOB msg1 = data_blob_null;
131 DATA_BLOB blob = data_blob_null;
132 DATA_BLOB blob_in = data_blob_null;
133 DATA_BLOB blob_out = data_blob_null;
134 struct berval cred, *scred = NULL;
135 int rc;
136 NTSTATUS nt_status;
137 ADS_STATUS status;
138 int turn = 1;
139 uint32 features = 0;
140
141 struct ntlmssp_state *ntlmssp_state;
142
143 nt_status = ntlmssp_client_start(NULL,
144 global_myname(),
145 lp_workgroup(),
146 lp_client_ntlmv2_auth(),
147 &ntlmssp_state);
148 if (!NT_STATUS_IS_OK(nt_status)) {
149 return ADS_ERROR_NT(nt_status);
150 }
151 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
152
153 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
154 return ADS_ERROR_NT(nt_status);
155 }
156 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
157 return ADS_ERROR_NT(nt_status);
158 }
159 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
160 return ADS_ERROR_NT(nt_status);
161 }
162
163 switch (ads->ldap.wrap_type) {
164 case ADS_SASLWRAP_TYPE_SEAL:
165 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
166 break;
167 case ADS_SASLWRAP_TYPE_SIGN:
168 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
169 features = NTLMSSP_FEATURE_SIGN;
170 } else {
171 /*
172 * windows servers are broken with sign only,
173 * so we need to use seal here too
174 */
175 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
176 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
177 }
178 break;
179 case ADS_SASLWRAP_TYPE_PLAIN:
180 break;
181 }
182
183 ntlmssp_want_feature(ntlmssp_state, features);
184
185 blob_in = data_blob_null;
186
187 do {
188 nt_status = ntlmssp_update(ntlmssp_state,
189 blob_in, &blob_out);
190 data_blob_free(&blob_in);
191 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
192 || NT_STATUS_IS_OK(nt_status))
193 && blob_out.length) {
194 if (turn == 1) {
195 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
196 /* and wrap it in a SPNEGO wrapper */
197 msg1 = spnego_gen_negTokenInit(talloc_tos(),
198 OIDs_ntlm, &blob_out, NULL);
199 } else {
200 /* wrap it in SPNEGO */
201 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
202 }
203
204 data_blob_free(&blob_out);
205
206 cred.bv_val = (char *)msg1.data;
207 cred.bv_len = msg1.length;
208 scred = NULL;
209 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
210 data_blob_free(&msg1);
211 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
212 if (scred) {
213 ber_bvfree(scred);
214 }
215
216 TALLOC_FREE(ntlmssp_state);
217 return ADS_ERROR(rc);
218 }
219 if (scred) {
220 blob = data_blob(scred->bv_val, scred->bv_len);
221 ber_bvfree(scred);
222 } else {
223 blob = data_blob_null;
224 }
225
226 } else {
227
228 TALLOC_FREE(ntlmssp_state);
229 data_blob_free(&blob_out);
230 return ADS_ERROR_NT(nt_status);
231 }
232
233 if ((turn == 1) &&
234 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
235 DATA_BLOB tmp_blob = data_blob_null;
236 /* the server might give us back two challenges */
237 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
238 &tmp_blob)) {
239
240 TALLOC_FREE(ntlmssp_state);
241 data_blob_free(&blob);
242 DEBUG(3,("Failed to parse challenges\n"));
243 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
244 }
245 data_blob_free(&tmp_blob);
246 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
247 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
248 &blob_in)) {
249
250 TALLOC_FREE(ntlmssp_state);
251 data_blob_free(&blob);
252 DEBUG(3,("Failed to parse auth response\n"));
253 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
254 }
255 }
256 data_blob_free(&blob);
257 data_blob_free(&blob_out);
258 turn++;
259 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
260
261 /* we have a reference conter on ntlmssp_state, if we are signing
262 then the state will be kept by the signing engine */
263
264 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
265 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
266 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
267 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
268 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
269 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
270 if (!ADS_ERR_OK(status)) {
271 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
272 ads_errstr(status)));
273 TALLOC_FREE(ntlmssp_state);
274 return status;
275 }
276 } else {
277 TALLOC_FREE(ntlmssp_state);
278 }
279
280 return ADS_ERROR(rc);
281}
282
283#ifdef HAVE_GSSAPI
284static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
285{
286 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
287 ADS_STATUS status;
288 int gss_rc;
289 uint32 minor_status;
290 gss_buffer_desc unwrapped, wrapped;
291 int conf_req_flag, conf_state;
292
293 unwrapped.value = buf;
294 unwrapped.length = len;
295
296 /* for now request sign and seal */
297 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
298
299 gss_rc = gss_wrap(&minor_status, context_handle,
300 conf_req_flag, GSS_C_QOP_DEFAULT,
301 &unwrapped, &conf_state,
302 &wrapped);
303 status = ADS_ERROR_GSS(gss_rc, minor_status);
304 if (!ADS_ERR_OK(status)) return status;
305
306 if (conf_req_flag && conf_state == 0) {
307 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
308 }
309
310 if ((ads->ldap.out.size - 4) < wrapped.length) {
311 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
312 }
313
314 /* copy the wrapped blob to the right location */
315 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
316
317 /* set how many bytes must be written to the underlying socket */
318 ads->ldap.out.left = 4 + wrapped.length;
319
320 gss_release_buffer(&minor_status, &wrapped);
321
322 return ADS_SUCCESS;
323}
324
325static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
326{
327 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
328 ADS_STATUS status;
329 int gss_rc;
330 uint32 minor_status;
331 gss_buffer_desc unwrapped, wrapped;
332 int conf_state;
333
334 wrapped.value = ads->ldap.in.buf + 4;
335 wrapped.length = ads->ldap.in.ofs - 4;
336
337 gss_rc = gss_unwrap(&minor_status, context_handle,
338 &wrapped, &unwrapped,
339 &conf_state, GSS_C_QOP_DEFAULT);
340 status = ADS_ERROR_GSS(gss_rc, minor_status);
341 if (!ADS_ERR_OK(status)) return status;
342
343 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
344 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
345 }
346
347 if (wrapped.length < unwrapped.length) {
348 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
349 }
350
351 /* copy the wrapped blob to the right location */
352 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
353
354 /* set how many bytes must be written to the underlying socket */
355 ads->ldap.in.left = unwrapped.length;
356 ads->ldap.in.ofs = 4;
357
358 gss_release_buffer(&minor_status, &unwrapped);
359
360 return ADS_SUCCESS;
361}
362
363static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
364{
365 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
366 uint32 minor_status;
367
368 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
369
370 ads->ldap.wrap_ops = NULL;
371 ads->ldap.wrap_private_data = NULL;
372}
373
374static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
375 .name = "gssapi",
376 .wrap = ads_sasl_gssapi_wrap,
377 .unwrap = ads_sasl_gssapi_unwrap,
378 .disconnect = ads_sasl_gssapi_disconnect
379};
380
381/*
382 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
383*/
384static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
385{
386 ADS_STATUS status;
387 bool ok;
388 uint32 minor_status;
389 int gss_rc, rc;
390 gss_OID_desc krb5_mech_type =
391 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
392 gss_OID mech_type = &krb5_mech_type;
393 gss_OID actual_mech_type = GSS_C_NULL_OID;
394 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
395 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
396 gss_buffer_desc input_token, output_token;
397 uint32 req_flags, ret_flags;
398 uint32 req_tmp, ret_tmp;
399 DATA_BLOB unwrapped;
400 DATA_BLOB wrapped;
401 struct berval cred, *scred = NULL;
402
403 input_token.value = NULL;
404 input_token.length = 0;
405
406 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
407 switch (ads->ldap.wrap_type) {
408 case ADS_SASLWRAP_TYPE_SEAL:
409 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
410 break;
411 case ADS_SASLWRAP_TYPE_SIGN:
412 req_flags |= GSS_C_INTEG_FLAG;
413 break;
414 case ADS_SASLWRAP_TYPE_PLAIN:
415 break;
416 }
417
418 /* Note: here we explicit ask for the krb5 mech_type */
419 gss_rc = gss_init_sec_context(&minor_status,
420 GSS_C_NO_CREDENTIAL,
421 &context_handle,
422 serv_name,
423 mech_type,
424 req_flags,
425 0,
426 NULL,
427 &input_token,
428 &actual_mech_type,
429 &output_token,
430 &ret_flags,
431 NULL);
432 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
433 status = ADS_ERROR_GSS(gss_rc, minor_status);
434 goto failed;
435 }
436
437 /*
438 * As some gssapi krb5 mech implementations
439 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
440 * to req_flags internaly, it's not possible to
441 * use plain or signing only connection via
442 * the gssapi interface.
443 *
444 * Because of this we need to check it the ret_flags
445 * has more flags as req_flags and correct the value
446 * of ads->ldap.wrap_type.
447 *
448 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
449 * we need to give an error.
450 */
451 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
452 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
453
454 if (req_tmp == ret_tmp) {
455 /* everythings fine... */
456
457 } else if (req_flags & GSS_C_CONF_FLAG) {
458 /*
459 * here we wanted sealing but didn't got it
460 * from the gssapi library
461 */
462 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
463 goto failed;
464
465 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
466 !(ret_flags & GSS_C_INTEG_FLAG)) {
467 /*
468 * here we wanted siging but didn't got it
469 * from the gssapi library
470 */
471 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
472 goto failed;
473
474 } else if (ret_flags & GSS_C_CONF_FLAG) {
475 /*
476 * here we didn't want sealing
477 * but the gssapi library forces it
478 * so correct the needed wrap_type if
479 * the caller didn't forced siging only
480 */
481 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
482 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
483 goto failed;
484 }
485
486 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
487 req_flags = ret_flags;
488
489 } else if (ret_flags & GSS_C_INTEG_FLAG) {
490 /*
491 * here we didn't want signing
492 * but the gssapi library forces it
493 * so correct the needed wrap_type if
494 * the caller didn't forced plain
495 */
496 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
497 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
498 goto failed;
499 }
500
501 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
502 req_flags = ret_flags;
503 } else {
504 /*
505 * This could (should?) not happen
506 */
507 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
508 goto failed;
509
510 }
511
512 /* and wrap that in a shiny SPNEGO wrapper */
513 unwrapped = data_blob_const(output_token.value, output_token.length);
514 wrapped = spnego_gen_negTokenInit(talloc_tos(),
515 spnego_mechs, &unwrapped, NULL);
516 gss_release_buffer(&minor_status, &output_token);
517 if (unwrapped.length > wrapped.length) {
518 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
519 goto failed;
520 }
521
522 cred.bv_val = (char *)wrapped.data;
523 cred.bv_len = wrapped.length;
524
525 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
526 &scred);
527 data_blob_free(&wrapped);
528 if (rc != LDAP_SUCCESS) {
529 status = ADS_ERROR(rc);
530 goto failed;
531 }
532
533 if (scred) {
534 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
535 } else {
536 wrapped = data_blob_null;
537 }
538
539 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
540 OID_KERBEROS5_OLD,
541 &unwrapped);
542 if (scred) ber_bvfree(scred);
543 if (!ok) {
544 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
545 goto failed;
546 }
547
548 input_token.value = unwrapped.data;
549 input_token.length = unwrapped.length;
550
551 /*
552 * As we asked for mutal authentication
553 * we need to pass the servers response
554 * to gssapi
555 */
556 gss_rc = gss_init_sec_context(&minor_status,
557 GSS_C_NO_CREDENTIAL,
558 &context_handle,
559 serv_name,
560 mech_type,
561 req_flags,
562 0,
563 NULL,
564 &input_token,
565 &actual_mech_type,
566 &output_token,
567 &ret_flags,
568 NULL);
569 data_blob_free(&unwrapped);
570 if (gss_rc) {
571 status = ADS_ERROR_GSS(gss_rc, minor_status);
572 goto failed;
573 }
574
575 gss_release_buffer(&minor_status, &output_token);
576
577 /*
578 * If we the sign and seal options
579 * doesn't match after getting the response
580 * from the server, we don't want to use the connection
581 */
582 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
583 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
584
585 if (req_tmp != ret_tmp) {
586 /* everythings fine... */
587 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
588 goto failed;
589 }
590
591 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
592 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
593
594 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
595 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
596 GSS_C_QOP_DEFAULT,
597 max_msg_size, &ads->ldap.out.max_unwrapped);
598 if (gss_rc) {
599 status = ADS_ERROR_GSS(gss_rc, minor_status);
600 goto failed;
601 }
602
603 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
604 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
605 ads->ldap.in.max_wrapped = max_msg_size;
606 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
607 if (!ADS_ERR_OK(status)) {
608 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
609 ads_errstr(status)));
610 goto failed;
611 }
612 /* make sure we don't free context_handle */
613 context_handle = GSS_C_NO_CONTEXT;
614 }
615
616 status = ADS_SUCCESS;
617
618failed:
619 if (context_handle != GSS_C_NO_CONTEXT)
620 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
621 return status;
622}
623
624#endif /* HAVE_GSSAPI */
625
626#ifdef HAVE_KRB5
627struct ads_service_principal {
628 char *string;
629#ifdef HAVE_GSSAPI
630 gss_name_t name;
631#endif
632};
633
634static void ads_free_service_principal(struct ads_service_principal *p)
635{
636 SAFE_FREE(p->string);
637
638#ifdef HAVE_GSSAPI
639 if (p->name) {
640 uint32 minor_status;
641 gss_release_name(&minor_status, &p->name);
642 }
643#endif
644 ZERO_STRUCTP(p);
645}
646
647
648static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
649 char **returned_principal)
650{
651 char *princ = NULL;
652
653 if (ads->server.realm && ads->server.ldap_server) {
654 char *server, *server_realm;
655
656 server = SMB_STRDUP(ads->server.ldap_server);
657 server_realm = SMB_STRDUP(ads->server.realm);
658
659 if (!server || !server_realm) {
660 SAFE_FREE(server);
661 SAFE_FREE(server_realm);
662 return ADS_ERROR(LDAP_NO_MEMORY);
663 }
664
665 strlower_m(server);
666 strupper_m(server_realm);
667 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
668 SAFE_FREE(server);
669 SAFE_FREE(server_realm);
670 return ADS_ERROR(LDAP_NO_MEMORY);
671 }
672
673 SAFE_FREE(server);
674 SAFE_FREE(server_realm);
675
676 if (!princ) {
677 return ADS_ERROR(LDAP_NO_MEMORY);
678 }
679 } else if (ads->config.realm && ads->config.ldap_server_name) {
680 char *server, *server_realm;
681
682 server = SMB_STRDUP(ads->config.ldap_server_name);
683 server_realm = SMB_STRDUP(ads->config.realm);
684
685 if (!server || !server_realm) {
686 SAFE_FREE(server);
687 SAFE_FREE(server_realm);
688 return ADS_ERROR(LDAP_NO_MEMORY);
689 }
690
691 strlower_m(server);
692 strupper_m(server_realm);
693 if (asprintf(&princ, "ldap/%s@%s", server, server_realm) == -1) {
694 SAFE_FREE(server);
695 SAFE_FREE(server_realm);
696 return ADS_ERROR(LDAP_NO_MEMORY);
697 }
698
699 SAFE_FREE(server);
700 SAFE_FREE(server_realm);
701
702 if (!princ) {
703 return ADS_ERROR(LDAP_NO_MEMORY);
704 }
705 }
706
707 if (!princ) {
708 return ADS_ERROR(LDAP_PARAM_ERROR);
709 }
710
711 *returned_principal = princ;
712
713 return ADS_SUCCESS;
714}
715
716static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
717 const char *given_principal,
718 struct ads_service_principal *p)
719{
720 ADS_STATUS status;
721#ifdef HAVE_GSSAPI
722 gss_buffer_desc input_name;
723 /* GSS_KRB5_NT_PRINCIPAL_NAME */
724 gss_OID_desc nt_principal =
725 {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
726 uint32 minor_status;
727 int gss_rc;
728#endif
729
730 ZERO_STRUCTP(p);
731
732 /* I've seen a child Windows 2000 domain not send
733 the principal name back in the first round of
734 the SASL bind reply. So we guess based on server
735 name and realm. --jerry */
736 /* Also try best guess when we get the w2k8 ignore principal
737 back, or when we are configured to ignore it - gd,
738 abartlet */
739
740 if (!lp_client_use_spnego_principal() ||
741 !given_principal ||
742 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
743
744 status = ads_guess_service_principal(ads, &p->string);
745 if (!ADS_ERR_OK(status)) {
746 return status;
747 }
748 } else {
749 p->string = SMB_STRDUP(given_principal);
750 if (!p->string) {
751 return ADS_ERROR(LDAP_NO_MEMORY);
752 }
753 }
754
755#ifdef HAVE_GSSAPI
756 input_name.value = p->string;
757 input_name.length = strlen(p->string);
758
759 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
760 if (gss_rc) {
761 ads_free_service_principal(p);
762 return ADS_ERROR_GSS(gss_rc, minor_status);
763 }
764#endif
765
766 return ADS_SUCCESS;
767}
768
769/*
770 perform a LDAP/SASL/SPNEGO/KRB5 bind
771*/
772static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
773{
774 DATA_BLOB blob = data_blob_null;
775 struct berval cred, *scred = NULL;
776 DATA_BLOB session_key = data_blob_null;
777 int rc;
778
779 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
780 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
781 }
782
783 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
784 ads->auth.time_offset, &blob, &session_key, 0,
785 &ads->auth.tgs_expire);
786
787 if (rc) {
788 return ADS_ERROR_KRB5(rc);
789 }
790
791 /* now send the auth packet and we should be done */
792 cred.bv_val = (char *)blob.data;
793 cred.bv_len = blob.length;
794
795 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
796
797 data_blob_free(&blob);
798 data_blob_free(&session_key);
799 if(scred)
800 ber_bvfree(scred);
801
802 return ADS_ERROR(rc);
803}
804
805static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
806 struct ads_service_principal *p)
807{
808#ifdef HAVE_GSSAPI
809 /*
810 * we only use the gsskrb5 based implementation
811 * when sasl sign or seal is requested.
812 *
813 * This has the following reasons:
814 * - it's likely that the gssapi krb5 mech implementation
815 * doesn't support to negotiate plain connections
816 * - the ads_sasl_spnego_rawkrb5_bind is more robust
817 * against clock skew errors
818 */
819 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
820 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
821 }
822#endif
823 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
824}
825#endif /* HAVE_KRB5 */
826
827/*
828 this performs a SASL/SPNEGO bind
829*/
830static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
831{
832 struct berval *scred=NULL;
833 int rc, i;
834 ADS_STATUS status;
835 DATA_BLOB blob;
836 char *given_principal = NULL;
837 char *OIDs[ASN1_MAX_OIDS];
838#ifdef HAVE_KRB5
839 bool got_kerberos_mechanism = False;
840#endif
841
842 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
843
844 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
845 status = ADS_ERROR(rc);
846 goto failed;
847 }
848
849 blob = data_blob(scred->bv_val, scred->bv_len);
850
851 ber_bvfree(scred);
852
853#if 0
854 file_save("sasl_spnego.dat", blob.data, blob.length);
855#endif
856
857 /* the server sent us the first part of the SPNEGO exchange in the negprot
858 reply */
859 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
860 OIDs[0] == NULL) {
861 data_blob_free(&blob);
862 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
863 goto failed;
864 }
865 data_blob_free(&blob);
866
867 /* make sure the server understands kerberos */
868 for (i=0;OIDs[i];i++) {
869 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
870#ifdef HAVE_KRB5
871 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
872 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
873 got_kerberos_mechanism = True;
874 }
875#endif
876 talloc_free(OIDs[i]);
877 }
878 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
879
880#ifdef HAVE_KRB5
881 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
882 got_kerberos_mechanism)
883 {
884 struct ads_service_principal p;
885
886 status = ads_generate_service_principal(ads, given_principal, &p);
887 TALLOC_FREE(given_principal);
888 if (!ADS_ERR_OK(status)) {
889 return status;
890 }
891
892 status = ads_sasl_spnego_krb5_bind(ads, &p);
893 if (ADS_ERR_OK(status)) {
894 ads_free_service_principal(&p);
895 return status;
896 }
897
898 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
899 "calling kinit\n", ads_errstr(status)));
900
901 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
902
903 if (ADS_ERR_OK(status)) {
904 status = ads_sasl_spnego_krb5_bind(ads, &p);
905 if (!ADS_ERR_OK(status)) {
906 DEBUG(0,("kinit succeeded but "
907 "ads_sasl_spnego_krb5_bind failed: %s\n",
908 ads_errstr(status)));
909 }
910 }
911
912 ads_free_service_principal(&p);
913
914 /* only fallback to NTLMSSP if allowed */
915 if (ADS_ERR_OK(status) ||
916 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
917 return status;
918 }
919 } else
920#endif
921 {
922 TALLOC_FREE(given_principal);
923 }
924
925 /* lets do NTLMSSP ... this has the big advantage that we don't need
926 to sync clocks, and we don't rely on special versions of the krb5
927 library for HMAC_MD4 encryption */
928 return ads_sasl_spnego_ntlmssp_bind(ads);
929
930failed:
931 return status;
932}
933
934#ifdef HAVE_GSSAPI
935#define MAX_GSS_PASSES 3
936
937/* this performs a SASL/gssapi bind
938 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
939 is very dependent on correctly configured DNS whereas
940 this routine is much less fragile
941 see RFC2078 and RFC2222 for details
942*/
943static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
944{
945 uint32 minor_status;
946 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
947 gss_OID mech_type = GSS_C_NULL_OID;
948 gss_buffer_desc output_token, input_token;
949 uint32 req_flags, ret_flags;
950 int conf_state;
951 struct berval cred;
952 struct berval *scred = NULL;
953 int i=0;
954 int gss_rc, rc;
955 uint8 *p;
956 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
957 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
958 ADS_STATUS status;
959
960 input_token.value = NULL;
961 input_token.length = 0;
962
963 /*
964 * Note: here we always ask the gssapi for sign and seal
965 * as this is negotiated later after the mutal
966 * authentication
967 */
968 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
969
970 for (i=0; i < MAX_GSS_PASSES; i++) {
971 gss_rc = gss_init_sec_context(&minor_status,
972 GSS_C_NO_CREDENTIAL,
973 &context_handle,
974 serv_name,
975 mech_type,
976 req_flags,
977 0,
978 NULL,
979 &input_token,
980 NULL,
981 &output_token,
982 &ret_flags,
983 NULL);
984 if (scred) {
985 ber_bvfree(scred);
986 scred = NULL;
987 }
988 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
989 status = ADS_ERROR_GSS(gss_rc, minor_status);
990 goto failed;
991 }
992
993 cred.bv_val = (char *)output_token.value;
994 cred.bv_len = output_token.length;
995
996 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
997 &scred);
998 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
999 status = ADS_ERROR(rc);
1000 goto failed;
1001 }
1002
1003 if (output_token.value) {
1004 gss_release_buffer(&minor_status, &output_token);
1005 }
1006
1007 if (scred) {
1008 input_token.value = scred->bv_val;
1009 input_token.length = scred->bv_len;
1010 } else {
1011 input_token.value = NULL;
1012 input_token.length = 0;
1013 }
1014
1015 if (gss_rc == 0) break;
1016 }
1017
1018 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1019 &conf_state,NULL);
1020 if (scred) {
1021 ber_bvfree(scred);
1022 scred = NULL;
1023 }
1024 if (gss_rc) {
1025 status = ADS_ERROR_GSS(gss_rc, minor_status);
1026 goto failed;
1027 }
1028
1029 p = (uint8 *)output_token.value;
1030
1031#if 0
1032 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1033#endif
1034
1035 if (p) {
1036 wrap_type = CVAL(p,0);
1037 SCVAL(p,0,0);
1038 max_msg_size = RIVAL(p,0);
1039 }
1040
1041 gss_release_buffer(&minor_status, &output_token);
1042
1043 if (!(wrap_type & ads->ldap.wrap_type)) {
1044 /*
1045 * the server doesn't supports the wrap
1046 * type we want :-(
1047 */
1048 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1049 ads->ldap.wrap_type, wrap_type));
1050 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1051 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1052 goto failed;
1053 }
1054
1055 /* 0x58 is the minimum windows accepts */
1056 if (max_msg_size < 0x58) {
1057 max_msg_size = 0x58;
1058 }
1059
1060 output_token.length = 4;
1061 output_token.value = SMB_MALLOC(output_token.length);
1062 if (!output_token.value) {
1063 output_token.length = 0;
1064 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1065 goto failed;
1066 }
1067 p = (uint8 *)output_token.value;
1068
1069 RSIVAL(p,0,max_msg_size);
1070 SCVAL(p,0,ads->ldap.wrap_type);
1071
1072 /*
1073 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1074 * but using ads->config.bind_path is the wrong! It should be
1075 * the DN of the user object!
1076 *
1077 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1078 * is ok and matches the information flow used in GSS-SPNEGO.
1079 */
1080
1081 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1082 &output_token, /* used as *input* here. */
1083 &conf_state,
1084 &input_token); /* Used as *output* here. */
1085 if (gss_rc) {
1086 status = ADS_ERROR_GSS(gss_rc, minor_status);
1087 output_token.length = 0;
1088 SAFE_FREE(output_token.value);
1089 goto failed;
1090 }
1091
1092 /* We've finished with output_token. */
1093 SAFE_FREE(output_token.value);
1094 output_token.length = 0;
1095
1096 cred.bv_val = (char *)input_token.value;
1097 cred.bv_len = input_token.length;
1098
1099 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1100 &scred);
1101 gss_release_buffer(&minor_status, &input_token);
1102 status = ADS_ERROR(rc);
1103 if (!ADS_ERR_OK(status)) {
1104 goto failed;
1105 }
1106
1107 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1108 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1109 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1110 GSS_C_QOP_DEFAULT,
1111 max_msg_size, &ads->ldap.out.max_unwrapped);
1112 if (gss_rc) {
1113 status = ADS_ERROR_GSS(gss_rc, minor_status);
1114 goto failed;
1115 }
1116
1117 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1118 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1119 ads->ldap.in.max_wrapped = max_msg_size;
1120 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1121 if (!ADS_ERR_OK(status)) {
1122 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1123 ads_errstr(status)));
1124 goto failed;
1125 }
1126 /* make sure we don't free context_handle */
1127 context_handle = GSS_C_NO_CONTEXT;
1128 }
1129
1130failed:
1131
1132 if (context_handle != GSS_C_NO_CONTEXT)
1133 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1134
1135 if(scred)
1136 ber_bvfree(scred);
1137 return status;
1138}
1139
1140static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1141{
1142 ADS_STATUS status;
1143 struct ads_service_principal p;
1144
1145 status = ads_generate_service_principal(ads, NULL, &p);
1146 if (!ADS_ERR_OK(status)) {
1147 return status;
1148 }
1149
1150 status = ads_sasl_gssapi_do_bind(ads, p.name);
1151 if (ADS_ERR_OK(status)) {
1152 ads_free_service_principal(&p);
1153 return status;
1154 }
1155
1156 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1157 "calling kinit\n", ads_errstr(status)));
1158
1159 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1160
1161 if (ADS_ERR_OK(status)) {
1162 status = ads_sasl_gssapi_do_bind(ads, p.name);
1163 }
1164
1165 ads_free_service_principal(&p);
1166
1167 return status;
1168}
1169
1170#endif /* HAVE_GSSAPI */
1171
1172/* mapping between SASL mechanisms and functions */
1173static struct {
1174 const char *name;
1175 ADS_STATUS (*fn)(ADS_STRUCT *);
1176} sasl_mechanisms[] = {
1177 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1178#ifdef HAVE_GSSAPI
1179 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1180#endif
1181 {NULL, NULL}
1182};
1183
1184ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1185{
1186 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1187 char **values;
1188 ADS_STATUS status;
1189 int i, j;
1190 LDAPMessage *res;
1191
1192 /* get a list of supported SASL mechanisms */
1193 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1194 if (!ADS_ERR_OK(status)) return status;
1195
1196 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1197
1198 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1199 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1200 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1201 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1202 } else {
1203 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1204 }
1205
1206 /* try our supported mechanisms in order */
1207 for (i=0;sasl_mechanisms[i].name;i++) {
1208 /* see if the server supports it */
1209 for (j=0;values && values[j];j++) {
1210 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1211 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1212retry:
1213 status = sasl_mechanisms[i].fn(ads);
1214 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1215 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1216 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1217 {
1218 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1219 "retrying with signing enabled\n"));
1220 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1221 goto retry;
1222 }
1223 ldap_value_free(values);
1224 ldap_msgfree(res);
1225 return status;
1226 }
1227 }
1228 }
1229
1230 ldap_value_free(values);
1231 ldap_msgfree(res);
1232 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1233}
1234
1235#endif /* HAVE_LDAP */
1236
Note: See TracBrowser for help on using the repository browser.