nfs4acls: Use talloc_realloc()
[Samba.git] / source3 / libads / sasl.c
blob720ee7852feb8375d631d47d917d3a1f02d43460
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 "auth/gensec/gensec.h"
23 #include "auth_generic.h"
24 #include "ads.h"
25 #include "smb_krb5.h"
26 #include "system/gssapi.h"
27 #include "lib/param/loadparm.h"
29 #ifdef HAVE_LDAP
31 static ADS_STATUS ads_sasl_ntlmssp_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
33 struct gensec_security *gensec_security =
34 talloc_get_type_abort(ads->ldap.wrap_private_data,
35 struct gensec_security);
36 NTSTATUS nt_status;
37 DATA_BLOB unwrapped, wrapped;
38 TALLOC_CTX *frame = talloc_stackframe();
40 unwrapped = data_blob_const(buf, len);
42 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
43 if (!NT_STATUS_IS_OK(nt_status)) {
44 TALLOC_FREE(frame);
45 return ADS_ERROR_NT(nt_status);
48 if ((ads->ldap.out.size - 4) < wrapped.length) {
49 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
52 /* copy the wrapped blob to the right location */
53 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
55 /* set how many bytes must be written to the underlying socket */
56 ads->ldap.out.left = 4 + wrapped.length;
58 TALLOC_FREE(frame);
60 return ADS_SUCCESS;
63 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
65 struct gensec_security *gensec_security =
66 talloc_get_type_abort(ads->ldap.wrap_private_data,
67 struct gensec_security);
68 NTSTATUS nt_status;
69 DATA_BLOB unwrapped, wrapped;
70 TALLOC_CTX *frame = talloc_stackframe();
72 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
74 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
75 if (!NT_STATUS_IS_OK(nt_status)) {
76 TALLOC_FREE(frame);
77 return ADS_ERROR_NT(nt_status);
80 if (wrapped.length < unwrapped.length) {
81 TALLOC_FREE(frame);
82 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
85 /* copy the wrapped blob to the right location */
86 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
88 /* set how many bytes must be written to the underlying socket */
89 ads->ldap.in.left = unwrapped.length;
90 ads->ldap.in.ofs = 4;
92 TALLOC_FREE(frame);
94 return ADS_SUCCESS;
97 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
99 struct gensec_security *gensec_security =
100 talloc_get_type_abort(ads->ldap.wrap_private_data,
101 struct gensec_security);
103 TALLOC_FREE(gensec_security);
105 ads->ldap.wrap_ops = NULL;
106 ads->ldap.wrap_private_data = NULL;
109 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
110 .name = "ntlmssp",
111 .wrap = ads_sasl_ntlmssp_wrap,
112 .unwrap = ads_sasl_ntlmssp_unwrap,
113 .disconnect = ads_sasl_ntlmssp_disconnect
117 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
118 we fit on one socket??)
120 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
122 DATA_BLOB msg1 = data_blob_null;
123 DATA_BLOB blob = data_blob_null;
124 DATA_BLOB blob_in = data_blob_null;
125 DATA_BLOB blob_out = data_blob_null;
126 struct berval cred, *scred = NULL;
127 int rc;
128 NTSTATUS nt_status;
129 ADS_STATUS status;
130 int turn = 1;
132 struct auth_generic_state *auth_generic_state;
134 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
135 if (!NT_STATUS_IS_OK(nt_status)) {
136 return ADS_ERROR_NT(nt_status);
139 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
140 return ADS_ERROR_NT(nt_status);
142 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
143 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
146 return ADS_ERROR_NT(nt_status);
149 switch (ads->ldap.wrap_type) {
150 case ADS_SASLWRAP_TYPE_SEAL:
151 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
152 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
153 break;
154 case ADS_SASLWRAP_TYPE_SIGN:
155 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
156 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
157 } else {
159 * windows servers are broken with sign only,
160 * so we need to use seal here too
162 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
163 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
164 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
166 break;
167 case ADS_SASLWRAP_TYPE_PLAIN:
168 break;
171 nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
172 if (!NT_STATUS_IS_OK(nt_status)) {
173 return ADS_ERROR_NT(nt_status);
176 blob_in = data_blob_null;
178 do {
179 nt_status = gensec_update(auth_generic_state->gensec_security,
180 talloc_tos(), blob_in, &blob_out);
181 data_blob_free(&blob_in);
182 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
183 || NT_STATUS_IS_OK(nt_status))
184 && blob_out.length) {
185 if (turn == 1) {
186 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
187 /* and wrap it in a SPNEGO wrapper */
188 msg1 = spnego_gen_negTokenInit(talloc_tos(),
189 OIDs_ntlm, &blob_out, NULL);
190 } else {
191 /* wrap it in SPNEGO */
192 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
195 data_blob_free(&blob_out);
197 cred.bv_val = (char *)msg1.data;
198 cred.bv_len = msg1.length;
199 scred = NULL;
200 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
201 data_blob_free(&msg1);
202 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
203 if (scred) {
204 ber_bvfree(scred);
207 TALLOC_FREE(auth_generic_state);
208 return ADS_ERROR(rc);
210 if (scred) {
211 blob = data_blob(scred->bv_val, scred->bv_len);
212 ber_bvfree(scred);
213 } else {
214 blob = data_blob_null;
217 } else {
219 TALLOC_FREE(auth_generic_state);
220 data_blob_free(&blob_out);
221 return ADS_ERROR_NT(nt_status);
224 if ((turn == 1) &&
225 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
226 DATA_BLOB tmp_blob = data_blob_null;
227 /* the server might give us back two challenges */
228 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
229 &tmp_blob)) {
231 TALLOC_FREE(auth_generic_state);
232 data_blob_free(&blob);
233 DEBUG(3,("Failed to parse challenges\n"));
234 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
236 data_blob_free(&tmp_blob);
237 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
238 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
239 &blob_in)) {
241 TALLOC_FREE(auth_generic_state);
242 data_blob_free(&blob);
243 DEBUG(3,("Failed to parse auth response\n"));
244 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
247 data_blob_free(&blob);
248 data_blob_free(&blob_out);
249 turn++;
250 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
252 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
253 size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
254 ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
256 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
257 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
258 ads->ldap.in.max_wrapped = max_wrapped;
259 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
260 if (!ADS_ERR_OK(status)) {
261 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
262 ads_errstr(status)));
263 TALLOC_FREE(auth_generic_state);
264 return status;
266 /* Only keep the gensec_security element around long-term */
267 talloc_steal(NULL, auth_generic_state->gensec_security);
269 TALLOC_FREE(auth_generic_state);
271 return ADS_ERROR(rc);
274 #ifdef HAVE_KRB5
275 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
277 ADS_STATUS status;
278 krb5_context kctx;
279 krb5_error_code kerr;
280 krb5_ccache kccache = NULL;
281 uint32_t maj, min;
283 *cred = GSS_C_NO_CREDENTIAL;
285 if (!ads->auth.ccache_name) {
286 return ADS_SUCCESS;
289 kerr = krb5_init_context(&kctx);
290 if (kerr) {
291 return ADS_ERROR_KRB5(kerr);
294 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
295 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
296 if (kerr) {
297 status = ADS_ERROR_KRB5(kerr);
298 goto done;
301 maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
302 if (maj != GSS_S_COMPLETE) {
303 status = ADS_ERROR_GSS(maj, min);
304 goto done;
306 #else
307 /* We need to fallback to overriding the default creds.
308 * This operation is not thread safe as it changes the process
309 * environment variable, but we do not have any better option
310 * with older kerberos libraries */
312 const char *oldccname = NULL;
314 oldccname = getenv("KRB5CCNAME");
315 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
317 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
318 NULL, GSS_C_INITIATE, cred, NULL, NULL);
320 if (oldccname) {
321 setenv("KRB5CCNAME", oldccname, 1);
322 } else {
323 unsetenv("KRB5CCNAME");
326 if (maj != GSS_S_COMPLETE) {
327 status = ADS_ERROR_GSS(maj, min);
328 goto done;
331 #endif
333 status = ADS_SUCCESS;
335 done:
336 if (!ADS_ERR_OK(status) && kccache != NULL) {
337 krb5_cc_close(kctx, kccache);
339 krb5_free_context(kctx);
340 return status;
343 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
345 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
346 ADS_STATUS status;
347 int gss_rc;
348 uint32_t minor_status;
349 gss_buffer_desc unwrapped, wrapped;
350 int conf_req_flag, conf_state;
352 unwrapped.value = buf;
353 unwrapped.length = len;
355 /* for now request sign and seal */
356 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
358 gss_rc = gss_wrap(&minor_status, context_handle,
359 conf_req_flag, GSS_C_QOP_DEFAULT,
360 &unwrapped, &conf_state,
361 &wrapped);
362 status = ADS_ERROR_GSS(gss_rc, minor_status);
363 if (!ADS_ERR_OK(status)) return status;
365 if (conf_req_flag && conf_state == 0) {
366 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
369 if ((ads->ldap.out.size - 4) < wrapped.length) {
370 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
373 /* copy the wrapped blob to the right location */
374 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
376 /* set how many bytes must be written to the underlying socket */
377 ads->ldap.out.left = 4 + wrapped.length;
379 gss_release_buffer(&minor_status, &wrapped);
381 return ADS_SUCCESS;
384 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
386 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
387 ADS_STATUS status;
388 int gss_rc;
389 uint32_t minor_status;
390 gss_buffer_desc unwrapped, wrapped;
391 int conf_state;
393 wrapped.value = ads->ldap.in.buf + 4;
394 wrapped.length = ads->ldap.in.ofs - 4;
396 gss_rc = gss_unwrap(&minor_status, context_handle,
397 &wrapped, &unwrapped,
398 &conf_state, GSS_C_QOP_DEFAULT);
399 status = ADS_ERROR_GSS(gss_rc, minor_status);
400 if (!ADS_ERR_OK(status)) return status;
402 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
403 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
406 if (wrapped.length < unwrapped.length) {
407 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
410 /* copy the wrapped blob to the right location */
411 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
413 /* set how many bytes must be written to the underlying socket */
414 ads->ldap.in.left = unwrapped.length;
415 ads->ldap.in.ofs = 4;
417 gss_release_buffer(&minor_status, &unwrapped);
419 return ADS_SUCCESS;
422 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
424 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
425 uint32_t minor_status;
427 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
429 ads->ldap.wrap_ops = NULL;
430 ads->ldap.wrap_private_data = NULL;
433 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
434 .name = "gssapi",
435 .wrap = ads_sasl_gssapi_wrap,
436 .unwrap = ads_sasl_gssapi_unwrap,
437 .disconnect = ads_sasl_gssapi_disconnect
441 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
443 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
445 ADS_STATUS status;
446 bool ok;
447 uint32_t minor_status;
448 int gss_rc, rc;
449 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
450 gss_OID_desc krb5_mech_type =
451 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
452 gss_OID mech_type = &krb5_mech_type;
453 gss_OID actual_mech_type = GSS_C_NULL_OID;
454 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
455 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
456 gss_buffer_desc input_token, output_token;
457 uint32_t req_flags, ret_flags;
458 uint32_t req_tmp, ret_tmp;
459 DATA_BLOB unwrapped;
460 DATA_BLOB wrapped;
461 struct berval cred, *scred = NULL;
462 uint32_t context_validity = 0;
463 time_t context_endtime = 0;
465 status = ads_init_gssapi_cred(ads, &gss_cred);
466 if (!ADS_ERR_OK(status)) {
467 goto failed;
470 input_token.value = NULL;
471 input_token.length = 0;
473 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
474 switch (ads->ldap.wrap_type) {
475 case ADS_SASLWRAP_TYPE_SEAL:
476 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
477 break;
478 case ADS_SASLWRAP_TYPE_SIGN:
479 req_flags |= GSS_C_INTEG_FLAG;
480 break;
481 case ADS_SASLWRAP_TYPE_PLAIN:
482 break;
485 /* Note: here we explicit ask for the krb5 mech_type */
486 gss_rc = gss_init_sec_context(&minor_status,
487 gss_cred,
488 &context_handle,
489 serv_name,
490 mech_type,
491 req_flags,
493 NULL,
494 &input_token,
495 &actual_mech_type,
496 &output_token,
497 &ret_flags,
498 NULL);
499 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
500 status = ADS_ERROR_GSS(gss_rc, minor_status);
501 goto failed;
505 * As some gssapi krb5 mech implementations
506 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
507 * to req_flags internaly, it's not possible to
508 * use plain or signing only connection via
509 * the gssapi interface.
511 * Because of this we need to check it the ret_flags
512 * has more flags as req_flags and correct the value
513 * of ads->ldap.wrap_type.
515 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
516 * we need to give an error.
518 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
519 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
521 if (req_tmp == ret_tmp) {
522 /* everythings fine... */
524 } else if (req_flags & GSS_C_CONF_FLAG) {
526 * here we wanted sealing but didn't got it
527 * from the gssapi library
529 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
530 goto failed;
532 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
533 !(ret_flags & GSS_C_INTEG_FLAG)) {
535 * here we wanted siging but didn't got it
536 * from the gssapi library
538 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
539 goto failed;
541 } else if (ret_flags & GSS_C_CONF_FLAG) {
543 * here we didn't want sealing
544 * but the gssapi library forces it
545 * so correct the needed wrap_type if
546 * the caller didn't forced siging only
548 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
549 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
550 goto failed;
553 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
554 req_flags = ret_flags;
556 } else if (ret_flags & GSS_C_INTEG_FLAG) {
558 * here we didn't want signing
559 * but the gssapi library forces it
560 * so correct the needed wrap_type if
561 * the caller didn't forced plain
563 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
564 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
565 goto failed;
568 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
569 req_flags = ret_flags;
570 } else {
572 * This could (should?) not happen
574 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
575 goto failed;
579 /* and wrap that in a shiny SPNEGO wrapper */
580 unwrapped = data_blob_const(output_token.value, output_token.length);
581 wrapped = spnego_gen_negTokenInit(talloc_tos(),
582 spnego_mechs, &unwrapped, NULL);
583 gss_release_buffer(&minor_status, &output_token);
584 if (unwrapped.length > wrapped.length) {
585 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
586 goto failed;
589 cred.bv_val = (char *)wrapped.data;
590 cred.bv_len = wrapped.length;
592 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
593 &scred);
594 data_blob_free(&wrapped);
595 if (rc != LDAP_SUCCESS) {
596 status = ADS_ERROR(rc);
597 goto failed;
600 if (scred) {
601 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
602 } else {
603 wrapped = data_blob_null;
606 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
607 OID_KERBEROS5_OLD,
608 &unwrapped);
609 if (scred) ber_bvfree(scred);
610 if (!ok) {
611 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
612 goto failed;
615 input_token.value = unwrapped.data;
616 input_token.length = unwrapped.length;
619 * As we asked for mutal authentication
620 * we need to pass the servers response
621 * to gssapi
623 gss_rc = gss_init_sec_context(&minor_status,
624 gss_cred,
625 &context_handle,
626 serv_name,
627 mech_type,
628 req_flags,
630 NULL,
631 &input_token,
632 &actual_mech_type,
633 &output_token,
634 &ret_flags,
635 NULL);
636 data_blob_free(&unwrapped);
637 if (gss_rc) {
638 status = ADS_ERROR_GSS(gss_rc, minor_status);
639 goto failed;
642 gss_release_buffer(&minor_status, &output_token);
645 * If we the sign and seal options
646 * doesn't match after getting the response
647 * from the server, we don't want to use the connection
649 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
650 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
652 if (req_tmp != ret_tmp) {
653 /* everythings fine... */
654 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
655 goto failed;
658 gss_rc =
659 gss_context_time(&minor_status, context_handle, &context_validity);
660 if (gss_rc == GSS_S_COMPLETE) {
661 if (context_validity != 0) {
662 context_endtime = time(NULL) + context_validity;
663 DEBUG(10, ("context (service ticket) valid for "
664 "%u seconds\n",
665 context_validity));
666 } else {
667 DEBUG(10, ("context (service ticket) expired\n"));
669 } else {
670 DEBUG(1, ("gss_context_time failed (%d,%u) -"
671 " this will be a one-time context\n",
672 gss_rc, minor_status));
673 if (gss_rc == GSS_S_CONTEXT_EXPIRED) {
674 DEBUG(10, ("context (service ticket) expired\n"));
678 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
679 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
681 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
682 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
683 GSS_C_QOP_DEFAULT,
684 max_msg_size, &ads->ldap.out.max_unwrapped);
685 if (gss_rc) {
686 status = ADS_ERROR_GSS(gss_rc, minor_status);
687 goto failed;
690 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
691 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
692 ads->ldap.in.max_wrapped = max_msg_size;
693 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
694 if (!ADS_ERR_OK(status)) {
695 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
696 ads_errstr(status)));
697 goto failed;
699 /* make sure we don't free context_handle */
700 context_handle = GSS_C_NO_CONTEXT;
703 ads->auth.tgs_expire = context_endtime;
704 status = ADS_SUCCESS;
706 failed:
707 if (gss_cred != GSS_C_NO_CREDENTIAL)
708 gss_release_cred(&minor_status, &gss_cred);
709 if (context_handle != GSS_C_NO_CONTEXT)
710 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
711 return status;
714 #endif /* HAVE_KRB5 */
716 #ifdef HAVE_KRB5
717 struct ads_service_principal {
718 char *string;
719 #ifdef HAVE_KRB5
720 gss_name_t name;
721 #endif
724 static void ads_free_service_principal(struct ads_service_principal *p)
726 SAFE_FREE(p->string);
728 #ifdef HAVE_KRB5
729 if (p->name) {
730 uint32_t minor_status;
731 gss_release_name(&minor_status, &p->name);
733 #endif
734 ZERO_STRUCTP(p);
738 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
739 char **returned_principal)
741 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
742 char *princ = NULL;
743 TALLOC_CTX *frame;
744 char *server = NULL;
745 char *realm = NULL;
746 int rc;
748 frame = talloc_stackframe();
749 if (frame == NULL) {
750 return ADS_ERROR(LDAP_NO_MEMORY);
753 if (ads->server.realm && ads->server.ldap_server) {
754 server = strlower_talloc(frame, ads->server.ldap_server);
755 if (server == NULL) {
756 goto out;
759 realm = strupper_talloc(frame, ads->server.realm);
760 if (realm == NULL) {
761 goto out;
765 * If we got a name which is bigger than a NetBIOS name,
766 * but isn't a FQDN, create one.
768 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
769 char *dnsdomain;
771 dnsdomain = strlower_talloc(frame, ads->server.realm);
772 if (dnsdomain == NULL) {
773 goto out;
776 server = talloc_asprintf(frame,
777 "%s.%s",
778 server, dnsdomain);
779 if (server == NULL) {
780 goto out;
783 } else if (ads->config.realm && ads->config.ldap_server_name) {
784 server = strlower_talloc(frame, ads->config.ldap_server_name);
785 if (server == NULL) {
786 goto out;
789 realm = strupper_talloc(frame, ads->config.realm);
790 if (realm == NULL) {
791 goto out;
795 * If we got a name which is bigger than a NetBIOS name,
796 * but isn't a FQDN, create one.
798 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
799 char *dnsdomain;
801 dnsdomain = strlower_talloc(frame, ads->server.realm);
802 if (dnsdomain == NULL) {
803 goto out;
806 server = talloc_asprintf(frame,
807 "%s.%s",
808 server, dnsdomain);
809 if (server == NULL) {
810 goto out;
815 if (server == NULL || realm == NULL) {
816 goto out;
819 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
820 if (rc == -1 || princ == NULL) {
821 status = ADS_ERROR(LDAP_PARAM_ERROR);
822 goto out;
825 *returned_principal = princ;
827 status = ADS_SUCCESS;
828 out:
829 TALLOC_FREE(frame);
830 return status;
833 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
834 const char *given_principal,
835 struct ads_service_principal *p)
837 ADS_STATUS status;
838 #ifdef HAVE_KRB5
839 gss_buffer_desc input_name;
840 /* GSS_KRB5_NT_PRINCIPAL_NAME */
841 gss_OID_desc nt_principal =
842 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
843 uint32_t minor_status;
844 int gss_rc;
845 #endif
847 ZERO_STRUCTP(p);
849 /* I've seen a child Windows 2000 domain not send
850 the principal name back in the first round of
851 the SASL bind reply. So we guess based on server
852 name and realm. --jerry */
853 /* Also try best guess when we get the w2k8 ignore principal
854 back, or when we are configured to ignore it - gd,
855 abartlet */
857 if (!lp_client_use_spnego_principal() ||
858 !given_principal ||
859 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
861 status = ads_guess_service_principal(ads, &p->string);
862 if (!ADS_ERR_OK(status)) {
863 return status;
865 } else {
866 p->string = SMB_STRDUP(given_principal);
867 if (!p->string) {
868 return ADS_ERROR(LDAP_NO_MEMORY);
872 #ifdef HAVE_KRB5
873 input_name.value = p->string;
874 input_name.length = strlen(p->string);
876 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
877 if (gss_rc) {
878 ads_free_service_principal(p);
879 return ADS_ERROR_GSS(gss_rc, minor_status);
881 #endif
883 return ADS_SUCCESS;
887 perform a LDAP/SASL/SPNEGO/KRB5 bind
889 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
891 DATA_BLOB blob = data_blob_null;
892 struct berval cred, *scred = NULL;
893 DATA_BLOB session_key = data_blob_null;
894 int rc;
896 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
897 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
900 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
901 ads->auth.time_offset, &blob, &session_key, 0,
902 ads->auth.ccache_name,
903 &ads->auth.tgs_expire);
905 if (rc) {
906 return ADS_ERROR_KRB5(rc);
909 /* now send the auth packet and we should be done */
910 cred.bv_val = (char *)blob.data;
911 cred.bv_len = blob.length;
913 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
915 data_blob_free(&blob);
916 data_blob_free(&session_key);
917 if(scred)
918 ber_bvfree(scred);
920 return ADS_ERROR(rc);
923 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
924 struct ads_service_principal *p)
926 #ifdef HAVE_KRB5
928 * we only use the gsskrb5 based implementation
929 * when sasl sign or seal is requested.
931 * This has the following reasons:
932 * - it's likely that the gssapi krb5 mech implementation
933 * doesn't support to negotiate plain connections
934 * - the ads_sasl_spnego_rawkrb5_bind is more robust
935 * against clock skew errors
937 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
938 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
940 #endif
941 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
943 #endif /* HAVE_KRB5 */
946 this performs a SASL/SPNEGO bind
948 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
950 struct berval *scred=NULL;
951 int rc, i;
952 ADS_STATUS status;
953 DATA_BLOB blob;
954 char *given_principal = NULL;
955 char *OIDs[ASN1_MAX_OIDS];
956 #ifdef HAVE_KRB5
957 bool got_kerberos_mechanism = False;
958 #endif
960 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
962 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
963 status = ADS_ERROR(rc);
964 goto failed;
967 blob = data_blob(scred->bv_val, scred->bv_len);
969 ber_bvfree(scred);
971 #if 0
972 file_save("sasl_spnego.dat", blob.data, blob.length);
973 #endif
975 /* the server sent us the first part of the SPNEGO exchange in the negprot
976 reply */
977 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
978 OIDs[0] == NULL) {
979 data_blob_free(&blob);
980 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
981 goto failed;
983 data_blob_free(&blob);
985 /* make sure the server understands kerberos */
986 for (i=0;OIDs[i];i++) {
987 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
988 #ifdef HAVE_KRB5
989 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
990 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
991 got_kerberos_mechanism = True;
993 #endif
994 talloc_free(OIDs[i]);
996 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
998 #ifdef HAVE_KRB5
999 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
1000 got_kerberos_mechanism)
1002 struct ads_service_principal p;
1004 status = ads_generate_service_principal(ads, given_principal, &p);
1005 TALLOC_FREE(given_principal);
1006 if (!ADS_ERR_OK(status)) {
1007 return status;
1010 status = ads_sasl_spnego_krb5_bind(ads, &p);
1011 if (ADS_ERR_OK(status)) {
1012 ads_free_service_principal(&p);
1013 return status;
1016 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
1017 "calling kinit\n", ads_errstr(status)));
1019 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1021 if (ADS_ERR_OK(status)) {
1022 status = ads_sasl_spnego_krb5_bind(ads, &p);
1023 if (!ADS_ERR_OK(status)) {
1024 DEBUG(0,("kinit succeeded but "
1025 "ads_sasl_spnego_krb5_bind failed: %s\n",
1026 ads_errstr(status)));
1030 ads_free_service_principal(&p);
1032 /* only fallback to NTLMSSP if allowed */
1033 if (ADS_ERR_OK(status) ||
1034 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
1035 return status;
1037 } else
1038 #endif
1040 TALLOC_FREE(given_principal);
1043 /* lets do NTLMSSP ... this has the big advantage that we don't need
1044 to sync clocks, and we don't rely on special versions of the krb5
1045 library for HMAC_MD4 encryption */
1046 return ads_sasl_spnego_ntlmssp_bind(ads);
1048 failed:
1049 return status;
1052 #ifdef HAVE_KRB5
1053 #define MAX_GSS_PASSES 3
1055 /* this performs a SASL/gssapi bind
1056 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
1057 is very dependent on correctly configured DNS whereas
1058 this routine is much less fragile
1059 see RFC2078 and RFC2222 for details
1061 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
1063 uint32_t minor_status;
1064 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
1065 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
1066 gss_OID mech_type = GSS_C_NULL_OID;
1067 gss_buffer_desc output_token, input_token;
1068 uint32_t req_flags, ret_flags;
1069 int conf_state;
1070 struct berval cred;
1071 struct berval *scred = NULL;
1072 int i=0;
1073 int gss_rc, rc;
1074 uint8_t *p;
1075 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
1076 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1077 ADS_STATUS status;
1079 input_token.value = NULL;
1080 input_token.length = 0;
1082 status = ads_init_gssapi_cred(ads, &gss_cred);
1083 if (!ADS_ERR_OK(status)) {
1084 goto failed;
1088 * Note: here we always ask the gssapi for sign and seal
1089 * as this is negotiated later after the mutal
1090 * authentication
1092 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
1094 for (i=0; i < MAX_GSS_PASSES; i++) {
1095 gss_rc = gss_init_sec_context(&minor_status,
1096 gss_cred,
1097 &context_handle,
1098 serv_name,
1099 mech_type,
1100 req_flags,
1102 NULL,
1103 &input_token,
1104 NULL,
1105 &output_token,
1106 &ret_flags,
1107 NULL);
1108 if (scred) {
1109 ber_bvfree(scred);
1110 scred = NULL;
1112 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
1113 status = ADS_ERROR_GSS(gss_rc, minor_status);
1114 goto failed;
1117 cred.bv_val = (char *)output_token.value;
1118 cred.bv_len = output_token.length;
1120 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1121 &scred);
1122 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
1123 status = ADS_ERROR(rc);
1124 goto failed;
1127 if (output_token.value) {
1128 gss_release_buffer(&minor_status, &output_token);
1131 if (scred) {
1132 input_token.value = scred->bv_val;
1133 input_token.length = scred->bv_len;
1134 } else {
1135 input_token.value = NULL;
1136 input_token.length = 0;
1139 if (gss_rc == 0) break;
1142 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1143 &conf_state,NULL);
1144 if (scred) {
1145 ber_bvfree(scred);
1146 scred = NULL;
1148 if (gss_rc) {
1149 status = ADS_ERROR_GSS(gss_rc, minor_status);
1150 goto failed;
1153 p = (uint8_t *)output_token.value;
1155 #if 0
1156 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1157 #endif
1159 if (p) {
1160 wrap_type = CVAL(p,0);
1161 SCVAL(p,0,0);
1162 max_msg_size = RIVAL(p,0);
1165 gss_release_buffer(&minor_status, &output_token);
1167 if (!(wrap_type & ads->ldap.wrap_type)) {
1169 * the server doesn't supports the wrap
1170 * type we want :-(
1172 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1173 ads->ldap.wrap_type, wrap_type));
1174 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1175 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1176 goto failed;
1179 /* 0x58 is the minimum windows accepts */
1180 if (max_msg_size < 0x58) {
1181 max_msg_size = 0x58;
1184 output_token.length = 4;
1185 output_token.value = SMB_MALLOC(output_token.length);
1186 if (!output_token.value) {
1187 output_token.length = 0;
1188 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1189 goto failed;
1191 p = (uint8_t *)output_token.value;
1193 RSIVAL(p,0,max_msg_size);
1194 SCVAL(p,0,ads->ldap.wrap_type);
1197 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1198 * but using ads->config.bind_path is the wrong! It should be
1199 * the DN of the user object!
1201 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1202 * is ok and matches the information flow used in GSS-SPNEGO.
1205 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1206 &output_token, /* used as *input* here. */
1207 &conf_state,
1208 &input_token); /* Used as *output* here. */
1209 if (gss_rc) {
1210 status = ADS_ERROR_GSS(gss_rc, minor_status);
1211 output_token.length = 0;
1212 SAFE_FREE(output_token.value);
1213 goto failed;
1216 /* We've finished with output_token. */
1217 SAFE_FREE(output_token.value);
1218 output_token.length = 0;
1220 cred.bv_val = (char *)input_token.value;
1221 cred.bv_len = input_token.length;
1223 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1224 &scred);
1225 gss_release_buffer(&minor_status, &input_token);
1226 status = ADS_ERROR(rc);
1227 if (!ADS_ERR_OK(status)) {
1228 goto failed;
1231 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1232 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1233 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1234 GSS_C_QOP_DEFAULT,
1235 max_msg_size, &ads->ldap.out.max_unwrapped);
1236 if (gss_rc) {
1237 status = ADS_ERROR_GSS(gss_rc, minor_status);
1238 goto failed;
1241 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1242 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1243 ads->ldap.in.max_wrapped = max_msg_size;
1244 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1245 if (!ADS_ERR_OK(status)) {
1246 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1247 ads_errstr(status)));
1248 goto failed;
1250 /* make sure we don't free context_handle */
1251 context_handle = GSS_C_NO_CONTEXT;
1254 failed:
1255 if (gss_cred != GSS_C_NO_CREDENTIAL)
1256 gss_release_cred(&minor_status, &gss_cred);
1257 if (context_handle != GSS_C_NO_CONTEXT)
1258 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1260 if(scred)
1261 ber_bvfree(scred);
1262 return status;
1265 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1267 ADS_STATUS status;
1268 struct ads_service_principal p;
1270 status = ads_generate_service_principal(ads, NULL, &p);
1271 if (!ADS_ERR_OK(status)) {
1272 return status;
1275 status = ads_sasl_gssapi_do_bind(ads, p.name);
1276 if (ADS_ERR_OK(status)) {
1277 ads_free_service_principal(&p);
1278 return status;
1281 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1282 "calling kinit\n", ads_errstr(status)));
1284 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1286 if (ADS_ERR_OK(status)) {
1287 status = ads_sasl_gssapi_do_bind(ads, p.name);
1290 ads_free_service_principal(&p);
1292 return status;
1295 #endif /* HAVE_KRB5 */
1297 /* mapping between SASL mechanisms and functions */
1298 static struct {
1299 const char *name;
1300 ADS_STATUS (*fn)(ADS_STRUCT *);
1301 } sasl_mechanisms[] = {
1302 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1303 #ifdef HAVE_KRB5
1304 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1305 #endif
1306 {NULL, NULL}
1309 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1311 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1312 char **values;
1313 ADS_STATUS status;
1314 int i, j;
1315 LDAPMessage *res;
1317 /* get a list of supported SASL mechanisms */
1318 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1319 if (!ADS_ERR_OK(status)) return status;
1321 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1323 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1324 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1325 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1326 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1327 } else {
1328 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1331 /* try our supported mechanisms in order */
1332 for (i=0;sasl_mechanisms[i].name;i++) {
1333 /* see if the server supports it */
1334 for (j=0;values && values[j];j++) {
1335 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1336 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1337 retry:
1338 status = sasl_mechanisms[i].fn(ads);
1339 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1340 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1341 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1343 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1344 "retrying with signing enabled\n"));
1345 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1346 goto retry;
1348 ldap_value_free(values);
1349 ldap_msgfree(res);
1350 return status;
1355 ldap_value_free(values);
1356 ldap_msgfree(res);
1357 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1360 #endif /* HAVE_LDAP */