s3:libads: add missing TALLOC_FREE(frame) in error path
[Samba.git] / source3 / libads / sasl.c
blobe1dd506d4a58b8d4515cd462f72fbbc3ce85e37a
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 TALLOC_FREE(frame);
50 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
53 /* copy the wrapped blob to the right location */
54 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
56 /* set how many bytes must be written to the underlying socket */
57 ads->ldap.out.left = 4 + wrapped.length;
59 TALLOC_FREE(frame);
61 return ADS_SUCCESS;
64 static ADS_STATUS ads_sasl_ntlmssp_unwrap(ADS_STRUCT *ads)
66 struct gensec_security *gensec_security =
67 talloc_get_type_abort(ads->ldap.wrap_private_data,
68 struct gensec_security);
69 NTSTATUS nt_status;
70 DATA_BLOB unwrapped, wrapped;
71 TALLOC_CTX *frame = talloc_stackframe();
73 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
75 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
76 if (!NT_STATUS_IS_OK(nt_status)) {
77 TALLOC_FREE(frame);
78 return ADS_ERROR_NT(nt_status);
81 if (wrapped.length < unwrapped.length) {
82 TALLOC_FREE(frame);
83 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
86 /* copy the wrapped blob to the right location */
87 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
89 /* set how many bytes must be written to the underlying socket */
90 ads->ldap.in.left = unwrapped.length;
91 ads->ldap.in.ofs = 4;
93 TALLOC_FREE(frame);
95 return ADS_SUCCESS;
98 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT *ads)
100 struct gensec_security *gensec_security =
101 talloc_get_type_abort(ads->ldap.wrap_private_data,
102 struct gensec_security);
104 TALLOC_FREE(gensec_security);
106 ads->ldap.wrap_ops = NULL;
107 ads->ldap.wrap_private_data = NULL;
110 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops = {
111 .name = "ntlmssp",
112 .wrap = ads_sasl_ntlmssp_wrap,
113 .unwrap = ads_sasl_ntlmssp_unwrap,
114 .disconnect = ads_sasl_ntlmssp_disconnect
118 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
119 we fit on one socket??)
121 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
123 DATA_BLOB msg1 = data_blob_null;
124 DATA_BLOB blob = data_blob_null;
125 DATA_BLOB blob_in = data_blob_null;
126 DATA_BLOB blob_out = data_blob_null;
127 struct berval cred, *scred = NULL;
128 int rc;
129 NTSTATUS nt_status;
130 ADS_STATUS status;
131 int turn = 1;
133 struct auth_generic_state *auth_generic_state;
135 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
136 if (!NT_STATUS_IS_OK(nt_status)) {
137 return ADS_ERROR_NT(nt_status);
140 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
141 return ADS_ERROR_NT(nt_status);
143 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
144 return ADS_ERROR_NT(nt_status);
146 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
147 return ADS_ERROR_NT(nt_status);
150 switch (ads->ldap.wrap_type) {
151 case ADS_SASLWRAP_TYPE_SEAL:
152 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
153 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
154 break;
155 case ADS_SASLWRAP_TYPE_SIGN:
156 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
157 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
158 } else {
160 * windows servers are broken with sign only,
161 * so we need to use seal here too
163 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
164 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
165 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
167 break;
168 case ADS_SASLWRAP_TYPE_PLAIN:
169 break;
172 nt_status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
173 if (!NT_STATUS_IS_OK(nt_status)) {
174 return ADS_ERROR_NT(nt_status);
177 blob_in = data_blob_null;
179 do {
180 nt_status = gensec_update(auth_generic_state->gensec_security,
181 talloc_tos(), blob_in, &blob_out);
182 data_blob_free(&blob_in);
183 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
184 || NT_STATUS_IS_OK(nt_status))
185 && blob_out.length) {
186 if (turn == 1) {
187 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
188 /* and wrap it in a SPNEGO wrapper */
189 msg1 = spnego_gen_negTokenInit(talloc_tos(),
190 OIDs_ntlm, &blob_out, NULL);
191 } else {
192 /* wrap it in SPNEGO */
193 msg1 = spnego_gen_auth(talloc_tos(), blob_out);
196 data_blob_free(&blob_out);
198 cred.bv_val = (char *)msg1.data;
199 cred.bv_len = msg1.length;
200 scred = NULL;
201 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
202 data_blob_free(&msg1);
203 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
204 if (scred) {
205 ber_bvfree(scred);
208 TALLOC_FREE(auth_generic_state);
209 return ADS_ERROR(rc);
211 if (scred) {
212 blob = data_blob(scred->bv_val, scred->bv_len);
213 ber_bvfree(scred);
214 } else {
215 blob = data_blob_null;
218 } else {
220 TALLOC_FREE(auth_generic_state);
221 data_blob_free(&blob_out);
222 return ADS_ERROR_NT(nt_status);
225 if ((turn == 1) &&
226 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
227 DATA_BLOB tmp_blob = data_blob_null;
228 /* the server might give us back two challenges */
229 if (!spnego_parse_challenge(talloc_tos(), blob, &blob_in,
230 &tmp_blob)) {
232 TALLOC_FREE(auth_generic_state);
233 data_blob_free(&blob);
234 DEBUG(3,("Failed to parse challenges\n"));
235 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
237 data_blob_free(&tmp_blob);
238 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
239 if (!spnego_parse_auth_response(talloc_tos(), blob, nt_status, OID_NTLMSSP,
240 &blob_in)) {
242 TALLOC_FREE(auth_generic_state);
243 data_blob_free(&blob);
244 DEBUG(3,("Failed to parse auth response\n"));
245 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
248 data_blob_free(&blob);
249 data_blob_free(&blob_out);
250 turn++;
251 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
253 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
254 size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
255 ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
257 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
258 ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
259 ads->ldap.in.max_wrapped = max_wrapped;
260 status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, auth_generic_state->gensec_security);
261 if (!ADS_ERR_OK(status)) {
262 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
263 ads_errstr(status)));
264 TALLOC_FREE(auth_generic_state);
265 return status;
267 /* Only keep the gensec_security element around long-term */
268 talloc_steal(NULL, auth_generic_state->gensec_security);
270 TALLOC_FREE(auth_generic_state);
272 return ADS_ERROR(rc);
275 #ifdef HAVE_KRB5
276 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
278 ADS_STATUS status;
279 krb5_context kctx;
280 krb5_error_code kerr;
281 krb5_ccache kccache = NULL;
282 uint32_t maj, min;
284 *cred = GSS_C_NO_CREDENTIAL;
286 if (!ads->auth.ccache_name) {
287 return ADS_SUCCESS;
290 kerr = krb5_init_context(&kctx);
291 if (kerr) {
292 return ADS_ERROR_KRB5(kerr);
295 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
296 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
297 if (kerr) {
298 status = ADS_ERROR_KRB5(kerr);
299 goto done;
302 maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
303 if (maj != GSS_S_COMPLETE) {
304 status = ADS_ERROR_GSS(maj, min);
305 goto done;
307 #else
308 /* We need to fallback to overriding the default creds.
309 * This operation is not thread safe as it changes the process
310 * environment variable, but we do not have any better option
311 * with older kerberos libraries */
313 const char *oldccname = NULL;
315 oldccname = getenv("KRB5CCNAME");
316 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
318 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
319 NULL, GSS_C_INITIATE, cred, NULL, NULL);
321 if (oldccname) {
322 setenv("KRB5CCNAME", oldccname, 1);
323 } else {
324 unsetenv("KRB5CCNAME");
327 if (maj != GSS_S_COMPLETE) {
328 status = ADS_ERROR_GSS(maj, min);
329 goto done;
332 #endif
334 status = ADS_SUCCESS;
336 done:
337 if (!ADS_ERR_OK(status) && kccache != NULL) {
338 krb5_cc_close(kctx, kccache);
340 krb5_free_context(kctx);
341 return status;
344 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
346 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
347 ADS_STATUS status;
348 int gss_rc;
349 uint32_t minor_status;
350 gss_buffer_desc unwrapped, wrapped;
351 int conf_req_flag, conf_state;
353 unwrapped.value = buf;
354 unwrapped.length = len;
356 /* for now request sign and seal */
357 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
359 gss_rc = gss_wrap(&minor_status, context_handle,
360 conf_req_flag, GSS_C_QOP_DEFAULT,
361 &unwrapped, &conf_state,
362 &wrapped);
363 status = ADS_ERROR_GSS(gss_rc, minor_status);
364 if (!ADS_ERR_OK(status)) return status;
366 if (conf_req_flag && conf_state == 0) {
367 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
370 if ((ads->ldap.out.size - 4) < wrapped.length) {
371 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
374 /* copy the wrapped blob to the right location */
375 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
377 /* set how many bytes must be written to the underlying socket */
378 ads->ldap.out.left = 4 + wrapped.length;
380 gss_release_buffer(&minor_status, &wrapped);
382 return ADS_SUCCESS;
385 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
387 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
388 ADS_STATUS status;
389 int gss_rc;
390 uint32_t minor_status;
391 gss_buffer_desc unwrapped, wrapped;
392 int conf_state;
394 wrapped.value = ads->ldap.in.buf + 4;
395 wrapped.length = ads->ldap.in.ofs - 4;
397 gss_rc = gss_unwrap(&minor_status, context_handle,
398 &wrapped, &unwrapped,
399 &conf_state, GSS_C_QOP_DEFAULT);
400 status = ADS_ERROR_GSS(gss_rc, minor_status);
401 if (!ADS_ERR_OK(status)) return status;
403 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
404 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
407 if (wrapped.length < unwrapped.length) {
408 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
411 /* copy the wrapped blob to the right location */
412 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
414 /* set how many bytes must be written to the underlying socket */
415 ads->ldap.in.left = unwrapped.length;
416 ads->ldap.in.ofs = 4;
418 gss_release_buffer(&minor_status, &unwrapped);
420 return ADS_SUCCESS;
423 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
425 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
426 uint32_t minor_status;
428 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
430 ads->ldap.wrap_ops = NULL;
431 ads->ldap.wrap_private_data = NULL;
434 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
435 .name = "gssapi",
436 .wrap = ads_sasl_gssapi_wrap,
437 .unwrap = ads_sasl_gssapi_unwrap,
438 .disconnect = ads_sasl_gssapi_disconnect
442 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
444 static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
446 ADS_STATUS status;
447 bool ok;
448 uint32_t minor_status;
449 int gss_rc, rc;
450 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
451 gss_OID_desc krb5_mech_type =
452 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
453 gss_OID mech_type = &krb5_mech_type;
454 gss_OID actual_mech_type = GSS_C_NULL_OID;
455 const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};
456 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
457 gss_buffer_desc input_token, output_token;
458 uint32_t req_flags, ret_flags;
459 uint32_t req_tmp, ret_tmp;
460 DATA_BLOB unwrapped;
461 DATA_BLOB wrapped;
462 struct berval cred, *scred = NULL;
463 uint32_t context_validity = 0;
464 time_t context_endtime = 0;
466 status = ads_init_gssapi_cred(ads, &gss_cred);
467 if (!ADS_ERR_OK(status)) {
468 goto failed;
471 input_token.value = NULL;
472 input_token.length = 0;
474 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
475 switch (ads->ldap.wrap_type) {
476 case ADS_SASLWRAP_TYPE_SEAL:
477 req_flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
478 break;
479 case ADS_SASLWRAP_TYPE_SIGN:
480 req_flags |= GSS_C_INTEG_FLAG;
481 break;
482 case ADS_SASLWRAP_TYPE_PLAIN:
483 break;
486 /* Note: here we explicit ask for the krb5 mech_type */
487 gss_rc = gss_init_sec_context(&minor_status,
488 gss_cred,
489 &context_handle,
490 serv_name,
491 mech_type,
492 req_flags,
494 NULL,
495 &input_token,
496 &actual_mech_type,
497 &output_token,
498 &ret_flags,
499 NULL);
500 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
501 status = ADS_ERROR_GSS(gss_rc, minor_status);
502 goto failed;
506 * As some gssapi krb5 mech implementations
507 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
508 * to req_flags internaly, it's not possible to
509 * use plain or signing only connection via
510 * the gssapi interface.
512 * Because of this we need to check it the ret_flags
513 * has more flags as req_flags and correct the value
514 * of ads->ldap.wrap_type.
516 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
517 * we need to give an error.
519 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
520 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
522 if (req_tmp == ret_tmp) {
523 /* everythings fine... */
525 } else if (req_flags & GSS_C_CONF_FLAG) {
527 * here we wanted sealing but didn't got it
528 * from the gssapi library
530 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
531 goto failed;
533 } else if ((req_flags & GSS_C_INTEG_FLAG) &&
534 !(ret_flags & GSS_C_INTEG_FLAG)) {
536 * here we wanted siging but didn't got it
537 * from the gssapi library
539 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
540 goto failed;
542 } else if (ret_flags & GSS_C_CONF_FLAG) {
544 * here we didn't want sealing
545 * but the gssapi library forces it
546 * so correct the needed wrap_type if
547 * the caller didn't forced siging only
549 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
550 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
551 goto failed;
554 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
555 req_flags = ret_flags;
557 } else if (ret_flags & GSS_C_INTEG_FLAG) {
559 * here we didn't want signing
560 * but the gssapi library forces it
561 * so correct the needed wrap_type if
562 * the caller didn't forced plain
564 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
565 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
566 goto failed;
569 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
570 req_flags = ret_flags;
571 } else {
573 * This could (should?) not happen
575 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
576 goto failed;
580 /* and wrap that in a shiny SPNEGO wrapper */
581 unwrapped = data_blob_const(output_token.value, output_token.length);
582 wrapped = spnego_gen_negTokenInit(talloc_tos(),
583 spnego_mechs, &unwrapped, NULL);
584 gss_release_buffer(&minor_status, &output_token);
585 if (unwrapped.length > wrapped.length) {
586 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
587 goto failed;
590 cred.bv_val = (char *)wrapped.data;
591 cred.bv_len = wrapped.length;
593 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL,
594 &scred);
595 data_blob_free(&wrapped);
596 if (rc != LDAP_SUCCESS) {
597 status = ADS_ERROR(rc);
598 goto failed;
601 if (scred) {
602 wrapped = data_blob_const(scred->bv_val, scred->bv_len);
603 } else {
604 wrapped = data_blob_null;
607 ok = spnego_parse_auth_response(talloc_tos(), wrapped, NT_STATUS_OK,
608 OID_KERBEROS5_OLD,
609 &unwrapped);
610 if (scred) ber_bvfree(scred);
611 if (!ok) {
612 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
613 goto failed;
616 input_token.value = unwrapped.data;
617 input_token.length = unwrapped.length;
620 * As we asked for mutal authentication
621 * we need to pass the servers response
622 * to gssapi
624 gss_rc = gss_init_sec_context(&minor_status,
625 gss_cred,
626 &context_handle,
627 serv_name,
628 mech_type,
629 req_flags,
631 NULL,
632 &input_token,
633 &actual_mech_type,
634 &output_token,
635 &ret_flags,
636 NULL);
637 data_blob_free(&unwrapped);
638 if (gss_rc) {
639 status = ADS_ERROR_GSS(gss_rc, minor_status);
640 goto failed;
643 gss_release_buffer(&minor_status, &output_token);
646 * If we the sign and seal options
647 * doesn't match after getting the response
648 * from the server, we don't want to use the connection
650 req_tmp = req_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
651 ret_tmp = ret_flags & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
653 if (req_tmp != ret_tmp) {
654 /* everythings fine... */
655 status = ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
656 goto failed;
659 gss_rc =
660 gss_context_time(&minor_status, context_handle, &context_validity);
661 if (gss_rc == GSS_S_COMPLETE) {
662 if (context_validity != 0) {
663 context_endtime = time(NULL) + context_validity;
664 DEBUG(10, ("context (service ticket) valid for "
665 "%u seconds\n",
666 context_validity));
667 } else {
668 DEBUG(10, ("context (service ticket) expired\n"));
670 } else {
671 DEBUG(1, ("gss_context_time failed (%d,%u) -"
672 " this will be a one-time context\n",
673 gss_rc, minor_status));
674 if (gss_rc == GSS_S_CONTEXT_EXPIRED) {
675 DEBUG(10, ("context (service ticket) expired\n"));
679 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
680 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
682 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
683 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
684 GSS_C_QOP_DEFAULT,
685 max_msg_size, &ads->ldap.out.max_unwrapped);
686 if (gss_rc) {
687 status = ADS_ERROR_GSS(gss_rc, minor_status);
688 goto failed;
691 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
692 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
693 ads->ldap.in.max_wrapped = max_msg_size;
694 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
695 if (!ADS_ERR_OK(status)) {
696 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
697 ads_errstr(status)));
698 goto failed;
700 /* make sure we don't free context_handle */
701 context_handle = GSS_C_NO_CONTEXT;
704 ads->auth.tgs_expire = context_endtime;
705 status = ADS_SUCCESS;
707 failed:
708 if (gss_cred != GSS_C_NO_CREDENTIAL)
709 gss_release_cred(&minor_status, &gss_cred);
710 if (context_handle != GSS_C_NO_CONTEXT)
711 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
712 return status;
715 #endif /* HAVE_KRB5 */
717 #ifdef HAVE_KRB5
718 struct ads_service_principal {
719 char *string;
720 #ifdef HAVE_KRB5
721 gss_name_t name;
722 #endif
725 static void ads_free_service_principal(struct ads_service_principal *p)
727 SAFE_FREE(p->string);
729 #ifdef HAVE_KRB5
730 if (p->name) {
731 uint32_t minor_status;
732 gss_release_name(&minor_status, &p->name);
734 #endif
735 ZERO_STRUCTP(p);
739 static ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
740 char **returned_principal)
742 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
743 char *princ = NULL;
744 TALLOC_CTX *frame;
745 char *server = NULL;
746 char *realm = NULL;
747 int rc;
749 frame = talloc_stackframe();
750 if (frame == NULL) {
751 return ADS_ERROR(LDAP_NO_MEMORY);
754 if (ads->server.realm && ads->server.ldap_server) {
755 server = strlower_talloc(frame, ads->server.ldap_server);
756 if (server == NULL) {
757 goto out;
760 realm = strupper_talloc(frame, ads->server.realm);
761 if (realm == NULL) {
762 goto out;
766 * If we got a name which is bigger than a NetBIOS name,
767 * but isn't a FQDN, create one.
769 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
770 char *dnsdomain;
772 dnsdomain = strlower_talloc(frame, ads->server.realm);
773 if (dnsdomain == NULL) {
774 goto out;
777 server = talloc_asprintf(frame,
778 "%s.%s",
779 server, dnsdomain);
780 if (server == NULL) {
781 goto out;
784 } else if (ads->config.realm && ads->config.ldap_server_name) {
785 server = strlower_talloc(frame, ads->config.ldap_server_name);
786 if (server == NULL) {
787 goto out;
790 realm = strupper_talloc(frame, ads->config.realm);
791 if (realm == NULL) {
792 goto out;
796 * If we got a name which is bigger than a NetBIOS name,
797 * but isn't a FQDN, create one.
799 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
800 char *dnsdomain;
802 dnsdomain = strlower_talloc(frame, ads->server.realm);
803 if (dnsdomain == NULL) {
804 goto out;
807 server = talloc_asprintf(frame,
808 "%s.%s",
809 server, dnsdomain);
810 if (server == NULL) {
811 goto out;
816 if (server == NULL || realm == NULL) {
817 goto out;
820 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
821 if (rc == -1 || princ == NULL) {
822 status = ADS_ERROR(LDAP_PARAM_ERROR);
823 goto out;
826 *returned_principal = princ;
828 status = ADS_SUCCESS;
829 out:
830 TALLOC_FREE(frame);
831 return status;
834 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
835 const char *given_principal,
836 struct ads_service_principal *p)
838 ADS_STATUS status;
839 #ifdef HAVE_KRB5
840 gss_buffer_desc input_name;
841 /* GSS_KRB5_NT_PRINCIPAL_NAME */
842 gss_OID_desc nt_principal =
843 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
844 uint32_t minor_status;
845 int gss_rc;
846 #endif
848 ZERO_STRUCTP(p);
850 /* I've seen a child Windows 2000 domain not send
851 the principal name back in the first round of
852 the SASL bind reply. So we guess based on server
853 name and realm. --jerry */
854 /* Also try best guess when we get the w2k8 ignore principal
855 back, or when we are configured to ignore it - gd,
856 abartlet */
858 if (!lp_client_use_spnego_principal() ||
859 !given_principal ||
860 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
862 status = ads_guess_service_principal(ads, &p->string);
863 if (!ADS_ERR_OK(status)) {
864 return status;
866 } else {
867 p->string = SMB_STRDUP(given_principal);
868 if (!p->string) {
869 return ADS_ERROR(LDAP_NO_MEMORY);
873 #ifdef HAVE_KRB5
874 input_name.value = p->string;
875 input_name.length = strlen(p->string);
877 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
878 if (gss_rc) {
879 ads_free_service_principal(p);
880 return ADS_ERROR_GSS(gss_rc, minor_status);
882 #endif
884 return ADS_SUCCESS;
888 perform a LDAP/SASL/SPNEGO/KRB5 bind
890 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
892 DATA_BLOB blob = data_blob_null;
893 struct berval cred, *scred = NULL;
894 DATA_BLOB session_key = data_blob_null;
895 int rc;
897 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
898 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
901 rc = spnego_gen_krb5_negTokenInit(talloc_tos(), principal,
902 ads->auth.time_offset, &blob, &session_key, 0,
903 ads->auth.ccache_name,
904 &ads->auth.tgs_expire);
906 if (rc) {
907 return ADS_ERROR_KRB5(rc);
910 /* now send the auth packet and we should be done */
911 cred.bv_val = (char *)blob.data;
912 cred.bv_len = blob.length;
914 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
916 data_blob_free(&blob);
917 data_blob_free(&session_key);
918 if(scred)
919 ber_bvfree(scred);
921 return ADS_ERROR(rc);
924 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
925 struct ads_service_principal *p)
927 #ifdef HAVE_KRB5
929 * we only use the gsskrb5 based implementation
930 * when sasl sign or seal is requested.
932 * This has the following reasons:
933 * - it's likely that the gssapi krb5 mech implementation
934 * doesn't support to negotiate plain connections
935 * - the ads_sasl_spnego_rawkrb5_bind is more robust
936 * against clock skew errors
938 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
939 return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
941 #endif
942 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
944 #endif /* HAVE_KRB5 */
947 this performs a SASL/SPNEGO bind
949 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
951 struct berval *scred=NULL;
952 int rc, i;
953 ADS_STATUS status;
954 DATA_BLOB blob;
955 char *given_principal = NULL;
956 char *OIDs[ASN1_MAX_OIDS];
957 #ifdef HAVE_KRB5
958 bool got_kerberos_mechanism = False;
959 #endif
961 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
963 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
964 status = ADS_ERROR(rc);
965 goto failed;
968 blob = data_blob(scred->bv_val, scred->bv_len);
970 ber_bvfree(scred);
972 #if 0
973 file_save("sasl_spnego.dat", blob.data, blob.length);
974 #endif
976 /* the server sent us the first part of the SPNEGO exchange in the negprot
977 reply */
978 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
979 OIDs[0] == NULL) {
980 data_blob_free(&blob);
981 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
982 goto failed;
984 data_blob_free(&blob);
986 /* make sure the server understands kerberos */
987 for (i=0;OIDs[i];i++) {
988 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
989 #ifdef HAVE_KRB5
990 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
991 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
992 got_kerberos_mechanism = True;
994 #endif
995 talloc_free(OIDs[i]);
997 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
999 #ifdef HAVE_KRB5
1000 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
1001 got_kerberos_mechanism)
1003 struct ads_service_principal p;
1005 status = ads_generate_service_principal(ads, given_principal, &p);
1006 TALLOC_FREE(given_principal);
1007 if (!ADS_ERR_OK(status)) {
1008 return status;
1011 status = ads_sasl_spnego_krb5_bind(ads, &p);
1012 if (ADS_ERR_OK(status)) {
1013 ads_free_service_principal(&p);
1014 return status;
1017 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
1018 "calling kinit\n", ads_errstr(status)));
1020 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1022 if (ADS_ERR_OK(status)) {
1023 status = ads_sasl_spnego_krb5_bind(ads, &p);
1024 if (!ADS_ERR_OK(status)) {
1025 DEBUG(0,("kinit succeeded but "
1026 "ads_sasl_spnego_krb5_bind failed: %s\n",
1027 ads_errstr(status)));
1031 ads_free_service_principal(&p);
1033 /* only fallback to NTLMSSP if allowed */
1034 if (ADS_ERR_OK(status) ||
1035 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
1036 return status;
1038 } else
1039 #endif
1041 TALLOC_FREE(given_principal);
1044 /* lets do NTLMSSP ... this has the big advantage that we don't need
1045 to sync clocks, and we don't rely on special versions of the krb5
1046 library for HMAC_MD4 encryption */
1047 return ads_sasl_spnego_ntlmssp_bind(ads);
1049 failed:
1050 return status;
1053 #ifdef HAVE_KRB5
1054 #define MAX_GSS_PASSES 3
1056 /* this performs a SASL/gssapi bind
1057 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
1058 is very dependent on correctly configured DNS whereas
1059 this routine is much less fragile
1060 see RFC2078 and RFC2222 for details
1062 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
1064 uint32_t minor_status;
1065 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
1066 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
1067 gss_OID mech_type = GSS_C_NULL_OID;
1068 gss_buffer_desc output_token, input_token;
1069 uint32_t req_flags, ret_flags;
1070 int conf_state;
1071 struct berval cred;
1072 struct berval *scred = NULL;
1073 int i=0;
1074 int gss_rc, rc;
1075 uint8_t *p;
1076 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
1077 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1078 ADS_STATUS status;
1080 input_token.value = NULL;
1081 input_token.length = 0;
1083 status = ads_init_gssapi_cred(ads, &gss_cred);
1084 if (!ADS_ERR_OK(status)) {
1085 goto failed;
1089 * Note: here we always ask the gssapi for sign and seal
1090 * as this is negotiated later after the mutal
1091 * authentication
1093 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
1095 for (i=0; i < MAX_GSS_PASSES; i++) {
1096 gss_rc = gss_init_sec_context(&minor_status,
1097 gss_cred,
1098 &context_handle,
1099 serv_name,
1100 mech_type,
1101 req_flags,
1103 NULL,
1104 &input_token,
1105 NULL,
1106 &output_token,
1107 &ret_flags,
1108 NULL);
1109 if (scred) {
1110 ber_bvfree(scred);
1111 scred = NULL;
1113 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
1114 status = ADS_ERROR_GSS(gss_rc, minor_status);
1115 goto failed;
1118 cred.bv_val = (char *)output_token.value;
1119 cred.bv_len = output_token.length;
1121 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1122 &scred);
1123 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
1124 status = ADS_ERROR(rc);
1125 goto failed;
1128 if (output_token.value) {
1129 gss_release_buffer(&minor_status, &output_token);
1132 if (scred) {
1133 input_token.value = scred->bv_val;
1134 input_token.length = scred->bv_len;
1135 } else {
1136 input_token.value = NULL;
1137 input_token.length = 0;
1140 if (gss_rc == 0) break;
1143 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
1144 &conf_state,NULL);
1145 if (scred) {
1146 ber_bvfree(scred);
1147 scred = NULL;
1149 if (gss_rc) {
1150 status = ADS_ERROR_GSS(gss_rc, minor_status);
1151 goto failed;
1154 p = (uint8_t *)output_token.value;
1156 #if 0
1157 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
1158 #endif
1160 if (p) {
1161 wrap_type = CVAL(p,0);
1162 SCVAL(p,0,0);
1163 max_msg_size = RIVAL(p,0);
1166 gss_release_buffer(&minor_status, &output_token);
1168 if (!(wrap_type & ads->ldap.wrap_type)) {
1170 * the server doesn't supports the wrap
1171 * type we want :-(
1173 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1174 ads->ldap.wrap_type, wrap_type));
1175 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1176 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
1177 goto failed;
1180 /* 0x58 is the minimum windows accepts */
1181 if (max_msg_size < 0x58) {
1182 max_msg_size = 0x58;
1185 output_token.length = 4;
1186 output_token.value = SMB_MALLOC(output_token.length);
1187 if (!output_token.value) {
1188 output_token.length = 0;
1189 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1190 goto failed;
1192 p = (uint8_t *)output_token.value;
1194 RSIVAL(p,0,max_msg_size);
1195 SCVAL(p,0,ads->ldap.wrap_type);
1198 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1199 * but using ads->config.bind_path is the wrong! It should be
1200 * the DN of the user object!
1202 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1203 * is ok and matches the information flow used in GSS-SPNEGO.
1206 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
1207 &output_token, /* used as *input* here. */
1208 &conf_state,
1209 &input_token); /* Used as *output* here. */
1210 if (gss_rc) {
1211 status = ADS_ERROR_GSS(gss_rc, minor_status);
1212 output_token.length = 0;
1213 SAFE_FREE(output_token.value);
1214 goto failed;
1217 /* We've finished with output_token. */
1218 SAFE_FREE(output_token.value);
1219 output_token.length = 0;
1221 cred.bv_val = (char *)input_token.value;
1222 cred.bv_len = input_token.length;
1224 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
1225 &scred);
1226 gss_release_buffer(&minor_status, &input_token);
1227 status = ADS_ERROR(rc);
1228 if (!ADS_ERR_OK(status)) {
1229 goto failed;
1232 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
1233 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
1234 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
1235 GSS_C_QOP_DEFAULT,
1236 max_msg_size, &ads->ldap.out.max_unwrapped);
1237 if (gss_rc) {
1238 status = ADS_ERROR_GSS(gss_rc, minor_status);
1239 goto failed;
1242 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
1243 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1244 ads->ldap.in.max_wrapped = max_msg_size;
1245 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
1246 if (!ADS_ERR_OK(status)) {
1247 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1248 ads_errstr(status)));
1249 goto failed;
1251 /* make sure we don't free context_handle */
1252 context_handle = GSS_C_NO_CONTEXT;
1255 failed:
1256 if (gss_cred != GSS_C_NO_CREDENTIAL)
1257 gss_release_cred(&minor_status, &gss_cred);
1258 if (context_handle != GSS_C_NO_CONTEXT)
1259 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1261 if(scred)
1262 ber_bvfree(scred);
1263 return status;
1266 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1268 ADS_STATUS status;
1269 struct ads_service_principal p;
1271 status = ads_generate_service_principal(ads, NULL, &p);
1272 if (!ADS_ERR_OK(status)) {
1273 return status;
1276 status = ads_sasl_gssapi_do_bind(ads, p.name);
1277 if (ADS_ERR_OK(status)) {
1278 ads_free_service_principal(&p);
1279 return status;
1282 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1283 "calling kinit\n", ads_errstr(status)));
1285 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1287 if (ADS_ERR_OK(status)) {
1288 status = ads_sasl_gssapi_do_bind(ads, p.name);
1291 ads_free_service_principal(&p);
1293 return status;
1296 #endif /* HAVE_KRB5 */
1298 /* mapping between SASL mechanisms and functions */
1299 static struct {
1300 const char *name;
1301 ADS_STATUS (*fn)(ADS_STRUCT *);
1302 } sasl_mechanisms[] = {
1303 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1304 #ifdef HAVE_KRB5
1305 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1306 #endif
1307 {NULL, NULL}
1310 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1312 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1313 char **values;
1314 ADS_STATUS status;
1315 int i, j;
1316 LDAPMessage *res;
1318 /* get a list of supported SASL mechanisms */
1319 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1320 if (!ADS_ERR_OK(status)) return status;
1322 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1324 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1325 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1326 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1327 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1328 } else {
1329 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1332 /* try our supported mechanisms in order */
1333 for (i=0;sasl_mechanisms[i].name;i++) {
1334 /* see if the server supports it */
1335 for (j=0;values && values[j];j++) {
1336 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1337 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1338 retry:
1339 status = sasl_mechanisms[i].fn(ads);
1340 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1341 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1342 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1344 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1345 "retrying with signing enabled\n"));
1346 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1347 goto retry;
1349 ldap_value_free(values);
1350 ldap_msgfree(res);
1351 return status;
1356 ldap_value_free(values);
1357 ldap_msgfree(res);
1358 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1361 #endif /* HAVE_LDAP */