s3: re-run make samba3-idl.
[Samba/cd1.git] / source3 / libads / sasl.c
blob6a0a1ae3d201b5aaabbbadfb560dcbea20ca5d36
1 /*
2 Unix SMB/CIFS implementation.
3 ads sasl code
4 Copyright (C) Andrew Tridgell 2001
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.
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.
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/>.
20 #include "includes.h"
21 #include "../libcli/auth/spnego.h"
22 #include "ntlmssp.h"
24 #ifdef HAVE_LDAP
26 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
28 struct ntlmssp_state *ntlmssp_state =
29 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
30 ADS_STATUS status;
31 NTSTATUS nt_status;
32 DATA_BLOB sig;
33 uint8 *dptr = ads->ldap.out.buf + (4 + NTLMSSP_SIG_SIZE);
35 /* copy the data to the right location */
36 memcpy(dptr, buf, len);
38 /* create the signature and may encrypt the data */
39 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
40 nt_status = ntlmssp_seal_packet(ntlmssp_state,
41 dptr, len,
42 dptr, len,
43 &sig);
44 } else {
45 nt_status = ntlmssp_sign_packet(ntlmssp_state,
46 dptr, len,
47 dptr, len,
48 &sig);
50 status = ADS_ERROR_NT(nt_status);
51 if (!ADS_ERR_OK(status)) return status;
53 /* copy the signature to the right location */
54 memcpy(ads->ldap.out.buf + 4,
55 sig.data, NTLMSSP_SIG_SIZE);
57 data_blob_free(&sig);
59 /* set how many bytes must be written to the underlying socket */
60 ads->ldap.out.left = 4 + NTLMSSP_SIG_SIZE + len;
62 return ADS_SUCCESS;
65 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
67 struct ntlmssp_state *ntlmssp_state =
68 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
69 ADS_STATUS status;
70 NTSTATUS nt_status;
71 DATA_BLOB sig;
72 uint8 *dptr = ads->ldap.in.buf + (4 + NTLMSSP_SIG_SIZE);
73 uint32 dlen = ads->ldap.in.ofs - (4 + NTLMSSP_SIG_SIZE);
75 /* wrap the signature into a DATA_BLOB */
76 sig = data_blob_const(ads->ldap.in.buf + 4, NTLMSSP_SIG_SIZE);
78 /* verify the signature and maybe decrypt the data */
79 if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
80 nt_status = ntlmssp_unseal_packet(ntlmssp_state,
81 dptr, dlen,
82 dptr, dlen,
83 &sig);
84 } else {
85 nt_status = ntlmssp_check_packet(ntlmssp_state,
86 dptr, dlen,
87 dptr, dlen,
88 &sig);
90 status = ADS_ERROR_NT(nt_status);
91 if (!ADS_ERR_OK(status)) return status;
93 /* set the amount of bytes for the upper layer and set the ofs to the data */
94 ads->ldap.in.left = dlen;
95 ads->ldap.in.ofs = 4 + NTLMSSP_SIG_SIZE;
97 return ADS_SUCCESS;
100 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
102 struct ntlmssp_state *ntlmssp_state =
103 (struct ntlmssp_state *)ads->ldap.wrap_private_data;
105 ntlmssp_end(&ntlmssp_state);
107 ads->ldap.wrap_ops = NULL;
108 ads->ldap.wrap_private_data = NULL;
111 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
112 .name = "ntlmssp",
113 .wrap = ads_sasl_ntlmssp_wrap,
114 .unwrap = ads_sasl_ntlmssp_unwrap,
115 .disconnect = ads_sasl_ntlmssp_disconnect
119 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
120 we fit on one socket??)
122 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
124 DATA_BLOB msg1 = data_blob_null;
125 DATA_BLOB blob = data_blob_null;
126 DATA_BLOB blob_in = data_blob_null;
127 DATA_BLOB blob_out = data_blob_null;
128 struct berval cred, *scred = NULL;
129 int rc;
130 NTSTATUS nt_status;
131 ADS_STATUS status;
132 int turn = 1;
133 uint32 features = 0;
135 struct ntlmssp_state *ntlmssp_state;
137 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
138 return ADS_ERROR_NT(nt_status);
140 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
142 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
143 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
146 return ADS_ERROR_NT(nt_status);
148 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
149 return ADS_ERROR_NT(nt_status);
152 switch (ads->ldap.wrap_type) {
153 case ADS_SASLWRAP_TYPE_SEAL:
154 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
155 break;
156 case ADS_SASLWRAP_TYPE_SIGN:
157 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
158 features = NTLMSSP_FEATURE_SIGN;
159 } else {
161 * windows servers are broken with sign only,
162 * so we need to use seal here too
164 features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
165 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
167 break;
168 case ADS_SASLWRAP_TYPE_PLAIN:
169 break;
172 ntlmssp_want_feature(ntlmssp_state, features);
174 blob_in = data_blob_null;
176 do {
177 nt_status = ntlmssp_update(ntlmssp_state,
178 blob_in, &blob_out);
179 data_blob_free(&blob_in);
180 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
181 || NT_STATUS_IS_OK(nt_status))
182 && blob_out.length) {
183 if (turn == 1) {
184 /* and wrap it in a SPNEGO wrapper */
185 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
186 } else {
187 /* wrap it in SPNEGO */
188 msg1 = spnego_gen_auth(blob_out);
191 data_blob_free(&blob_out);
193 cred.bv_val = (char *)msg1.data;
194 cred.bv_len = msg1.length;
195 scred = NULL;
196 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
197 data_blob_free(&msg1);
198 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
199 if (scred) {
200 ber_bvfree(scred);
203 ntlmssp_end(&ntlmssp_state);
204 return ADS_ERROR(rc);
206 if (scred) {
207 blob = data_blob(scred->bv_val, scred->bv_len);
208 ber_bvfree(scred);
209 } else {
210 blob = data_blob_null;
213 } else {
215 ntlmssp_end(&ntlmssp_state);
216 data_blob_free(&blob_out);
217 return ADS_ERROR_NT(nt_status);
220 if ((turn == 1) &&
221 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
222 DATA_BLOB tmp_blob = data_blob_null;
223 /* the server might give us back two challenges */
224 if (!spnego_parse_challenge(blob, &blob_in,
225 &tmp_blob)) {
227 ntlmssp_end(&ntlmssp_state);
228 data_blob_free(&blob);
229 DEBUG(3,("Failed to parse challenges\n"));
230 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
232 data_blob_free(&tmp_blob);
233 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
234 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
235 &blob_in)) {
237 ntlmssp_end(&ntlmssp_state);
238 data_blob_free(&blob);
239 DEBUG(3,("Failed to parse auth response\n"));
240 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
243 data_blob_free(&blob);
244 data_blob_free(&blob_out);
245 turn++;
246 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
248 /* we have a reference conter on ntlmssp_state, if we are signing
249 then the state will be kept by the signing engine */
251 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
252 ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
253 ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
254 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
255 ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
256 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
257 if (!ADS_ERR_OK(status)) {
258 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
259 ads_errstr(status)));
260 ntlmssp_end(&ntlmssp_state);
261 return status;
263 } else {
264 ntlmssp_end(&ntlmssp_state);
267 return ADS_ERROR(rc);
270 #ifdef HAVE_GSSAPI
271 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8 *buf, uint32 len)
273 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
274 ADS_STATUS status;
275 int gss_rc;
276 uint32 minor_status;
277 gss_buffer_desc unwrapped, wrapped;
278 int conf_req_flag, conf_state;
280 unwrapped.value = buf;
281 unwrapped.length = len;
283 /* for now request sign and seal */
284 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
286 gss_rc = gss_wrap(&minor_status, context_handle,
287 conf_req_flag, GSS_C_QOP_DEFAULT,
288 &unwrapped, &conf_state,
289 &wrapped);
290 status = ADS_ERROR_GSS(gss_rc, minor_status);
291 if (!ADS_ERR_OK(status)) return status;
293 if (conf_req_flag && conf_state == 0) {
294 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
297 if ((ads->ldap.out.size - 4) < wrapped.length) {
298 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
301 /* copy the wrapped blob to the right location */
302 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
304 /* set how many bytes must be written to the underlying socket */
305 ads->ldap.out.left = 4 + wrapped.length;
307 gss_release_buffer(&minor_status, &wrapped);
309 return ADS_SUCCESS;
312 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
314 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
315 ADS_STATUS status;
316 int gss_rc;
317 uint32 minor_status;
318 gss_buffer_desc unwrapped, wrapped;
319 int conf_state;
321 wrapped.value = ads->ldap.in.buf + 4;
322 wrapped.length = ads->ldap.in.ofs - 4;
324 gss_rc = gss_unwrap(&minor_status, context_handle,
325 &wrapped, &unwrapped,
326 &conf_state, GSS_C_QOP_DEFAULT);
327 status = ADS_ERROR_GSS(gss_rc, minor_status);
328 if (!ADS_ERR_OK(status)) return status;
330 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
331 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
334 if (wrapped.length < unwrapped.length) {
335 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
338 /* copy the wrapped blob to the right location */
339 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
341 /* set how many bytes must be written to the underlying socket */
342 ads->ldap.in.left = unwrapped.length;
343 ads->ldap.in.ofs = 4;
345 gss_release_buffer(&minor_status, &unwrapped);
347 return ADS_SUCCESS;
350 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
352 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
353 uint32 minor_status;
355 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
357 ads->ldap.wrap_ops = NULL;
358 ads->ldap.wrap_private_data = NULL;
361 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
362 .name = "gssapi",
363 .wrap = ads_sasl_gssapi_wrap,
364 .unwrap = ads_sasl_gssapi_unwrap,
365 .disconnect = ads_sasl_gssapi_disconnect
369 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
371 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
373 ADS_STATUS status;
374 bool ok;
375 uint32 minor_status;
376 int gss_rc, rc;
377 gss_OID_desc krb5_mech_type =
378 {9, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
379 gss_OID mech_type = &krb5_mech_type;
380 gss_OID actual_mech_type = GSS_C_NULL_OID;
381 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
382 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
383 gss_buffer_desc input_token, output_token;
384 uint32 req_flags, ret_flags;
385 uint32 req_tmp, ret_tmp;
386 DATA_BLOB unwrapped;
387 DATA_BLOB wrapped;
388 struct berval cred, *scred = NULL;
390 input_token.value = NULL;
391 input_token.length = 0;
393 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
394 switch (ads->ldap.wrap_type) {
395 case ADS_SASLWRAP_TYPE_SEAL:
396 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
397 break;
398 case ADS_SASLWRAP_TYPE_SIGN:
399 req_flags |= GSS_C_INTEG_FLAG;
400 break;
401 case ADS_SASLWRAP_TYPE_PLAIN:
402 break;
405 /* Note: here we explicit ask for the krb5 mech_type */
406 gss_rc = gss_init_sec_context(&minor_status,
407 GSS_C_NO_CREDENTIAL,
408 &context_handle,
409 serv_name,
410 mech_type,
411 req_flags,
413 NULL,
414 &input_token,
415 &actual_mech_type,
416 &output_token,
417 &ret_flags,
418 NULL);
419 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
420 status = ADS_ERROR_GSS(gss_rc, minor_status);
421 goto failed;
425 * As some gssapi krb5 mech implementations
426 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
427 * to req_flags internaly, it's not possible to
428 * use plain or signing only connection via
429 * the gssapi interface.
431 * Because of this we need to check it the ret_flags
432 * has more flags as req_flags and correct the value
433 * of ads->ldap.wrap_type.
435 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
436 * we need to give an error.
438 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
439 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
441 if (req_tmp == ret_tmp) {
442 /* everythings fine... */
444 } else if (req_flags & GSS_C_CONF_FLAG) {
446 * here we wanted sealing but didn't got it
447 * from the gssapi library
449 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
450 goto failed;
452 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
453 !(ret_flags & GSS_C_INTEG_FLAG)) {
455 * here we wanted siging but didn't got it
456 * from the gssapi library
458 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
459 goto failed;
461 } else if (ret_flags & GSS_C_CONF_FLAG) {
463 * here we didn't want sealing
464 * but the gssapi library forces it
465 * so correct the needed wrap_type if
466 * the caller didn't forced siging only
468 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
469 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
470 goto failed;
473 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
474 req_flags = ret_flags;
476 } else if (ret_flags & GSS_C_INTEG_FLAG) {
478 * here we didn't want signing
479 * but the gssapi library forces it
480 * so correct the needed wrap_type if
481 * the caller didn't forced plain
483 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
484 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
485 goto failed;
488 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
489 req_flags = ret_flags;
490 } else {
492 * This could (should?) not happen
494 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
495 goto failed;
499 /* and wrap that in a shiny SPNEGO wrapper */
500 unwrapped = data_blob_const(output_token.value, output_token.length);
501 wrapped = gen_negTokenTarg(spnego_mechs, unwrapped);
502 gss_release_buffer(&minor_status, &output_token);
503 if (unwrapped.length > wrapped.length) {
504 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
505 goto failed;
508 cred.bv_val = (char *)wrapped.data;
509 cred.bv_len = wrapped.length;
511 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
512 &scred);
513 data_blob_free(&wrapped);
514 if (rc != LDAP_SUCCESS) {
515 status = ADS_ERROR(rc);
516 goto failed;
519 if (scred) {
520 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
521 } else {
522 wrapped = data_blob_null;
525 ok = spnego_parse_auth_response(wrapped, NT_STATUS_OK,
526 OID_KERBEROS5_OLD,
527 &unwrapped);
528 if (scred) ber_bvfree(scred);
529 if (!ok) {
530 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
531 goto failed;
534 input_token.value = unwrapped.data;
535 input_token.length = unwrapped.length;
538 * As we asked for mutal authentication
539 * we need to pass the servers response
540 * to gssapi
542 gss_rc = gss_init_sec_context(&minor_status,
543 GSS_C_NO_CREDENTIAL,
544 &context_handle,
545 serv_name,
546 mech_type,
547 req_flags,
549 NULL,
550 &input_token,
551 &actual_mech_type,
552 &output_token,
553 &ret_flags,
554 NULL);
555 data_blob_free(&unwrapped);
556 if (gss_rc) {
557 status = ADS_ERROR_GSS(gss_rc, minor_status);
558 goto failed;
561 gss_release_buffer(&minor_status, &output_token);
564 * If we the sign and seal options
565 * doesn't match after getting the response
566 * from the server, we don't want to use the connection
568 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
569 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
571 if (req_tmp != ret_tmp) {
572 /* everythings fine... */
573 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
574 goto failed;
577 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
578 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
580 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
581 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
582 GSS_C_QOP_DEFAULT,
583 max_msg_size, &ads->ldap.out.max_unwrapped);
584 if (gss_rc) {
585 status = ADS_ERROR_GSS(gss_rc, minor_status);
586 goto failed;
589 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
590 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
591 ads->ldap.in.max_wrapped = max_msg_size;
592 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
593 if (!ADS_ERR_OK(status)) {
594 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
595 ads_errstr(status)));
596 goto failed;
598 /* make sure we don't free context_handle */
599 context_handle = GSS_C_NO_CONTEXT;
602 status = ADS_SUCCESS;
604 failed:
605 if (context_handle != GSS_C_NO_CONTEXT)
606 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
607 return status;
610 #endif /* HAVE_GSSAPI */
612 #ifdef HAVE_KRB5
613 struct ads_service_principal {
614 char *string;
615 #ifdef HAVE_GSSAPI
616 gss_name_t name;
617 #endif
620 static void ads_free_service_principal(struct ads_service_principal *p)
622 SAFE_FREE(p->string);
624 #ifdef HAVE_GSSAPI
625 if (p->name) {
626 uint32 minor_status;
627 gss_release_name(&minor_status, &p->name);
629 #endif
630 ZERO_STRUCTP(p);
633 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
634 const char *given_principal,
635 struct ads_service_principal *p)
637 ADS_STATUS status;
638 #ifdef HAVE_GSSAPI
639 gss_buffer_desc input_name;
640 /* GSS_KRB5_NT_PRINCIPAL_NAME */
641 gss_OID_desc nt_principal =
642 {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
643 uint32 minor_status;
644 int gss_rc;
645 #endif
647 ZERO_STRUCTP(p);
649 /* I've seen a child Windows 2000 domain not send
650 the principal name back in the first round of
651 the SASL bind reply. So we guess based on server
652 name and realm. --jerry */
653 /* Also try best guess when we get the w2k8 ignore
654 principal back - gd */
656 if (!given_principal ||
657 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
659 status = ads_guess_service_principal(ads, &p->string);
660 if (!ADS_ERR_OK(status)) {
661 return status;
663 } else {
664 p->string = SMB_STRDUP(given_principal);
665 if (!p->string) {
666 return ADS_ERROR(LDAP_NO_MEMORY);
670 #ifdef HAVE_GSSAPI
671 input_name.value = p->string;
672 input_name.length = strlen(p->string);
674 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
675 if (gss_rc) {
676 ads_free_service_principal(p);
677 return ADS_ERROR_GSS(gss_rc, minor_status);
679 #endif
681 return ADS_SUCCESS;
685 perform a LDAP/SASL/SPNEGO/KRB5 bind
687 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
689 DATA_BLOB blob = data_blob_null;
690 struct berval cred, *scred = NULL;
691 DATA_BLOB session_key = data_blob_null;
692 int rc;
694 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
695 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
698 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
699 &ads->auth.tgs_expire);
701 if (rc) {
702 return ADS_ERROR_KRB5(rc);
705 /* now send the auth packet and we should be done */
706 cred.bv_val = (char *)blob.data;
707 cred.bv_len = blob.length;
709 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
711 data_blob_free(&blob);
712 data_blob_free(&session_key);
713 if(scred)
714 ber_bvfree(scred);
716 return ADS_ERROR(rc);
719 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
720 struct ads_service_principal *p)
722 #ifdef HAVE_GSSAPI
724 * we only use the gsskrb5 based implementation
725 * when sasl sign or seal is requested.
727 * This has the following reasons:
728 * - it's likely that the gssapi krb5 mech implementation
729 * doesn't support to negotiate plain connections
730 * - the ads_sasl_spnego_rawkrb5_bind is more robust
731 * against clock skew errors
733 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
734 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
736 #endif
737 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
739 #endif /* HAVE_KRB5 */
742 this performs a SASL/SPNEGO bind
744 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
746 struct berval *scred=NULL;
747 int rc, i;
748 ADS_STATUS status;
749 DATA_BLOB blob;
750 char *given_principal = NULL;
751 char *OIDs[ASN1_MAX_OIDS];
752 #ifdef HAVE_KRB5
753 bool got_kerberos_mechanism = False;
754 #endif
756 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
758 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
759 status = ADS_ERROR(rc);
760 goto failed;
763 blob = data_blob(scred->bv_val, scred->bv_len);
765 ber_bvfree(scred);
767 #if 0
768 file_save("sasl_spnego.dat", blob.data, blob.length);
769 #endif
771 /* the server sent us the first part of the SPNEGO exchange in the negprot
772 reply */
773 if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
774 data_blob_free(&blob);
775 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
776 goto failed;
778 data_blob_free(&blob);
780 /* make sure the server understands kerberos */
781 for (i=0;OIDs[i];i++) {
782 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
783 #ifdef HAVE_KRB5
784 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
785 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
786 got_kerberos_mechanism = True;
788 #endif
789 talloc_free(OIDs[i]);
791 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
793 #ifdef HAVE_KRB5
794 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
795 got_kerberos_mechanism)
797 struct ads_service_principal p;
799 status = ads_generate_service_principal(ads, given_principal, &p);
800 TALLOC_FREE(given_principal);
801 if (!ADS_ERR_OK(status)) {
802 return status;
805 status = ads_sasl_spnego_krb5_bind(ads, &p);
806 if (ADS_ERR_OK(status)) {
807 ads_free_service_principal(&p);
808 return status;
811 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
812 "calling kinit\n", ads_errstr(status)));
814 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
816 if (ADS_ERR_OK(status)) {
817 status = ads_sasl_spnego_krb5_bind(ads, &p);
818 if (!ADS_ERR_OK(status)) {
819 DEBUG(0,("kinit succeeded but "
820 "ads_sasl_spnego_krb5_bind failed: %s\n",
821 ads_errstr(status)));
825 ads_free_service_principal(&p);
827 /* only fallback to NTLMSSP if allowed */
828 if (ADS_ERR_OK(status) ||
829 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
830 return status;
832 } else
833 #endif
835 TALLOC_FREE(given_principal);
838 /* lets do NTLMSSP ... this has the big advantage that we don't need
839 to sync clocks, and we don't rely on special versions of the krb5
840 library for HMAC_MD4 encryption */
841 return ads_sasl_spnego_ntlmssp_bind(ads);
843 failed:
844 return status;
847 #ifdef HAVE_GSSAPI
848 #define MAX_GSS_PASSES 3
850 /* this performs a SASL/gssapi bind
851 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
852 is very dependent on correctly configured DNS whereas
853 this routine is much less fragile
854 see RFC2078 and RFC2222 for details
856 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
858 uint32 minor_status;
859 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
860 gss_OID mech_type = GSS_C_NULL_OID;
861 gss_buffer_desc output_token, input_token;
862 uint32 req_flags, ret_flags;
863 int conf_state;
864 struct berval cred;
865 struct berval *scred = NULL;
866 int i=0;
867 int gss_rc, rc;
868 uint8 *p;
869 uint32 max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
870 uint8 wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
871 ADS_STATUS status;
873 input_token.value = NULL;
874 input_token.length = 0;
877 * Note: here we always ask the gssapi for sign and seal
878 * as this is negotiated later after the mutal
879 * authentication
881 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
883 for (i=0; i < MAX_GSS_PASSES; i++) {
884 gss_rc = gss_init_sec_context(&minor_status,
885 GSS_C_NO_CREDENTIAL,
886 &context_handle,
887 serv_name,
888 mech_type,
889 req_flags,
891 NULL,
892 &input_token,
893 NULL,
894 &output_token,
895 &ret_flags,
896 NULL);
897 if (scred) {
898 ber_bvfree(scred);
899 scred = NULL;
901 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
902 status = ADS_ERROR_GSS(gss_rc, minor_status);
903 goto failed;
906 cred.bv_val = (char *)output_token.value;
907 cred.bv_len = output_token.length;
909 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
910 &scred);
911 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
912 status = ADS_ERROR(rc);
913 goto failed;
916 if (output_token.value) {
917 gss_release_buffer(&minor_status, &output_token);
920 if (scred) {
921 input_token.value = scred->bv_val;
922 input_token.length = scred->bv_len;
923 } else {
924 input_token.value = NULL;
925 input_token.length = 0;
928 if (gss_rc == 0) break;
931 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
932 &conf_state,NULL);
933 if (scred) {
934 ber_bvfree(scred);
935 scred = NULL;
937 if (gss_rc) {
938 status = ADS_ERROR_GSS(gss_rc, minor_status);
939 goto failed;
942 p = (uint8 *)output_token.value;
944 #if 0
945 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
946 #endif
948 if (p) {
949 wrap_type = CVAL(p,0);
950 SCVAL(p,0,0);
951 max_msg_size = RIVAL(p,0);
954 gss_release_buffer(&minor_status, &output_token);
956 if (!(wrap_type & ads->ldap.wrap_type)) {
958 * the server doesn't supports the wrap
959 * type we want :-(
961 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
962 ads->ldap.wrap_type, wrap_type));
963 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
964 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
965 goto failed;
968 /* 0x58 is the minimum windows accepts */
969 if (max_msg_size < 0x58) {
970 max_msg_size = 0x58;
973 output_token.length = 4;
974 output_token.value = SMB_MALLOC(output_token.length);
975 p = (uint8 *)output_token.value;
977 RSIVAL(p,0,max_msg_size);
978 SCVAL(p,0,ads->ldap.wrap_type);
981 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
982 * but using ads->config.bind_path is the wrong! It should be
983 * the DN of the user object!
985 * w2k3 gives an error when we send an incorrect DN, but sending nothing
986 * is ok and matches the information flow used in GSS-SPNEGO.
989 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
990 &output_token, &conf_state,
991 &input_token);
992 if (gss_rc) {
993 status = ADS_ERROR_GSS(gss_rc, minor_status);
994 goto failed;
997 free(output_token.value);
999 cred.bv_val = (char *)input_token.value;
1000 cred.bv_len = input_token.length;
1002 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1003 &scred);
1004 gss_release_buffer(&minor_status, &input_token);
1005 status = ADS_ERROR(rc);
1006 if (!ADS_ERR_OK(status)) {
1007 goto failed;
1010 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1011 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1012 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1013 GSS_C_QOP_DEFAULT,
1014 max_msg_size, &ads->ldap.out.max_unwrapped);
1015 if (gss_rc) {
1016 status = ADS_ERROR_GSS(gss_rc, minor_status);
1017 goto failed;
1020 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1021 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1022 ads->ldap.in.max_wrapped = max_msg_size;
1023 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1024 if (!ADS_ERR_OK(status)) {
1025 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1026 ads_errstr(status)));
1027 goto failed;
1029 /* make sure we don't free context_handle */
1030 context_handle = GSS_C_NO_CONTEXT;
1033 failed:
1035 if (context_handle != GSS_C_NO_CONTEXT)
1036 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1038 if(scred)
1039 ber_bvfree(scred);
1040 return status;
1043 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1045 ADS_STATUS status;
1046 struct ads_service_principal p;
1048 status = ads_generate_service_principal(ads, NULL, &p);
1049 if (!ADS_ERR_OK(status)) {
1050 return status;
1053 status = ads_sasl_gssapi_do_bind(ads, p.name);
1054 if (ADS_ERR_OK(status)) {
1055 ads_free_service_principal(&p);
1056 return status;
1059 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1060 "calling kinit\n", ads_errstr(status)));
1062 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1064 if (ADS_ERR_OK(status)) {
1065 status = ads_sasl_gssapi_do_bind(ads, p.name);
1068 ads_free_service_principal(&p);
1070 return status;
1073 #endif /* HAVE_GSSAPI */
1075 /* mapping between SASL mechanisms and functions */
1076 static struct {
1077 const char *name;
1078 ADS_STATUS (*fn)(ADS_STRUCT *);
1079 } sasl_mechanisms[] = {
1080 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1081 #ifdef HAVE_GSSAPI
1082 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1083 #endif
1084 {NULL, NULL}
1087 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1089 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1090 char **values;
1091 ADS_STATUS status;
1092 int i, j;
1093 LDAPMessage *res;
1095 /* get a list of supported SASL mechanisms */
1096 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1097 if (!ADS_ERR_OK(status)) return status;
1099 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1101 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1102 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1103 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1104 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1105 } else {
1106 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1109 /* try our supported mechanisms in order */
1110 for (i=0;sasl_mechanisms[i].name;i++) {
1111 /* see if the server supports it */
1112 for (j=0;values && values[j];j++) {
1113 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1114 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1115 status = sasl_mechanisms[i].fn(ads);
1116 ldap_value_free(values);
1117 ldap_msgfree(res);
1118 return status;
1123 ldap_value_free(values);
1124 ldap_msgfree(res);
1125 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1128 #endif /* HAVE_LDAP */