2 Unix SMB/CIFS implementation.
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/>.
21 #include "../libcli/auth/spnego.h"
22 #include "auth/gensec/gensec.h"
23 #include "auth_generic.h"
26 #include "system/gssapi.h"
27 #include "lib/param/loadparm.h"
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
);
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
)) {
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
;
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
);
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
)) {
77 return ADS_ERROR_NT(nt_status
);
80 if (wrapped
.length
< unwrapped
.length
) {
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
;
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
= {
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
;
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
);
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
);
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
;
167 case ADS_SASLWRAP_TYPE_PLAIN
:
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
;
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
) {
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
);
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
;
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)) {
207 TALLOC_FREE(auth_generic_state
);
208 return ADS_ERROR(rc
);
211 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
214 blob
= data_blob_null
;
219 TALLOC_FREE(auth_generic_state
);
220 data_blob_free(&blob_out
);
221 return ADS_ERROR_NT(nt_status
);
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
,
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
,
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
);
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
);
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
);
275 static ADS_STATUS
ads_init_gssapi_cred(ADS_STRUCT
*ads
, gss_cred_id_t
*cred
)
279 krb5_error_code kerr
;
280 krb5_ccache kccache
= NULL
;
283 *cred
= GSS_C_NO_CREDENTIAL
;
285 if (!ads
->auth
.ccache_name
) {
289 kerr
= krb5_init_context(&kctx
);
291 return ADS_ERROR_KRB5(kerr
);
294 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
295 kerr
= krb5_cc_resolve(kctx
, ads
->auth
.ccache_name
, &kccache
);
297 status
= ADS_ERROR_KRB5(kerr
);
301 maj
= gss_krb5_import_cred(&min
, kccache
, NULL
, NULL
, cred
);
302 if (maj
!= GSS_S_COMPLETE
) {
303 status
= ADS_ERROR_GSS(maj
, min
);
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
);
321 setenv("KRB5CCNAME", oldccname
, 1);
323 unsetenv("KRB5CCNAME");
326 if (maj
!= GSS_S_COMPLETE
) {
327 status
= ADS_ERROR_GSS(maj
, min
);
333 status
= ADS_SUCCESS
;
336 if (!ADS_ERR_OK(status
) && kccache
!= NULL
) {
337 krb5_cc_close(kctx
, kccache
);
339 krb5_free_context(kctx
);
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
;
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
,
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
);
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
;
389 uint32_t minor_status
;
390 gss_buffer_desc unwrapped
, wrapped
;
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
);
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
= {
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
)
447 uint32_t minor_status
;
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
;
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
)) {
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
;
478 case ADS_SASLWRAP_TYPE_SIGN
:
479 req_flags
|= GSS_C_INTEG_FLAG
;
481 case ADS_SASLWRAP_TYPE_PLAIN
:
485 /* Note: here we explicit ask for the krb5 mech_type */
486 gss_rc
= gss_init_sec_context(&minor_status
,
499 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
500 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
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
);
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
);
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
);
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
);
568 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
569 req_flags
= ret_flags
;
572 * This could (should?) not happen
574 status
= ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
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
);
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
,
594 data_blob_free(&wrapped
);
595 if (rc
!= LDAP_SUCCESS
) {
596 status
= ADS_ERROR(rc
);
601 wrapped
= data_blob_const(scred
->bv_val
, scred
->bv_len
);
603 wrapped
= data_blob_null
;
606 ok
= spnego_parse_auth_response(talloc_tos(), wrapped
, NT_STATUS_OK
,
609 if (scred
) ber_bvfree(scred
);
611 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
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
623 gss_rc
= gss_init_sec_context(&minor_status
,
636 data_blob_free(&unwrapped
);
638 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
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
);
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 "
667 DEBUG(10, ("context (service ticket) expired\n"));
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
),
684 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
686 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
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
)));
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
;
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
);
714 #endif /* HAVE_KRB5 */
717 struct ads_service_principal
{
724 static void ads_free_service_principal(struct ads_service_principal
*p
)
726 SAFE_FREE(p
->string
);
730 uint32_t minor_status
;
731 gss_release_name(&minor_status
, &p
->name
);
738 static ADS_STATUS
ads_guess_service_principal(ADS_STRUCT
*ads
,
739 char **returned_principal
)
741 ADS_STATUS status
= ADS_ERROR(LDAP_NO_MEMORY
);
748 frame
= talloc_stackframe();
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
) {
759 realm
= strupper_talloc(frame
, ads
->server
.realm
);
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
) {
771 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
772 if (dnsdomain
== NULL
) {
776 server
= talloc_asprintf(frame
,
779 if (server
== NULL
) {
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
) {
789 realm
= strupper_talloc(frame
, ads
->config
.realm
);
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
) {
801 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
802 if (dnsdomain
== NULL
) {
806 server
= talloc_asprintf(frame
,
809 if (server
== NULL
) {
815 if (server
== NULL
|| realm
== NULL
) {
819 rc
= asprintf(&princ
, "ldap/%s@%s", server
, realm
);
820 if (rc
== -1 || princ
== NULL
) {
821 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
825 *returned_principal
= princ
;
827 status
= ADS_SUCCESS
;
833 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
834 const char *given_principal
,
835 struct ads_service_principal
*p
)
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
;
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,
857 if (!lp_client_use_spnego_principal() ||
859 strequal(given_principal
, ADS_IGNORE_PRINCIPAL
)) {
861 status
= ads_guess_service_principal(ads
, &p
->string
);
862 if (!ADS_ERR_OK(status
)) {
866 p
->string
= SMB_STRDUP(given_principal
);
868 return ADS_ERROR(LDAP_NO_MEMORY
);
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
);
878 ads_free_service_principal(p
);
879 return ADS_ERROR_GSS(gss_rc
, minor_status
);
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
;
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
);
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
);
920 return ADS_ERROR(rc
);
923 static ADS_STATUS
ads_sasl_spnego_krb5_bind(ADS_STRUCT
*ads
,
924 struct ads_service_principal
*p
)
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
);
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
;
954 char *given_principal
= NULL
;
955 char *OIDs
[ASN1_MAX_OIDS
];
957 bool got_kerberos_mechanism
= False
;
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
);
967 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
972 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
975 /* the server sent us the first part of the SPNEGO exchange in the negprot
977 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
979 data_blob_free(&blob
);
980 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
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
]));
989 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
990 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
991 got_kerberos_mechanism
= True
;
994 talloc_free(OIDs
[i
]);
996 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal
));
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
)) {
1010 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
1011 if (ADS_ERR_OK(status
)) {
1012 ads_free_service_principal(&p
);
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
)) {
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
);
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
;
1071 struct berval
*scred
= NULL
;
1075 uint32_t max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
1076 uint8_t wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
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
)) {
1088 * Note: here we always ask the gssapi for sign and seal
1089 * as this is negotiated later after the mutal
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
,
1112 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
1113 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
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
,
1122 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
1123 status
= ADS_ERROR(rc
);
1127 if (output_token
.value
) {
1128 gss_release_buffer(&minor_status
, &output_token
);
1132 input_token
.value
= scred
->bv_val
;
1133 input_token
.length
= scred
->bv_len
;
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
,
1149 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1153 p
= (uint8_t *)output_token
.value
;
1156 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
1160 wrap_type
= CVAL(p
,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
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
);
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
);
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. */
1208 &input_token
); /* Used as *output* here. */
1210 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1211 output_token
.length
= 0;
1212 SAFE_FREE(output_token
.value
);
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
,
1225 gss_release_buffer(&minor_status
, &input_token
);
1226 status
= ADS_ERROR(rc
);
1227 if (!ADS_ERR_OK(status
)) {
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
),
1235 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
1237 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
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
)));
1250 /* make sure we don't free context_handle */
1251 context_handle
= GSS_C_NO_CONTEXT
;
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
);
1265 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1268 struct ads_service_principal p
;
1270 status
= ads_generate_service_principal(ads
, NULL
, &p
);
1271 if (!ADS_ERR_OK(status
)) {
1275 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1276 if (ADS_ERR_OK(status
)) {
1277 ads_free_service_principal(&p
);
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
);
1295 #endif /* HAVE_KRB5 */
1297 /* mapping between SASL mechanisms and functions */
1300 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1301 } sasl_mechanisms
[] = {
1302 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1304 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1309 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1311 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
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
;
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
]));
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
;
1348 ldap_value_free(values
);
1355 ldap_value_free(values
);
1357 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1360 #endif /* HAVE_LDAP */