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
*buf
, uint32 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 uint32_t sig_size
= gensec_sig_size(auth_generic_state
->gensec_security
, 0);
254 ads
->ldap
.out
.max_unwrapped
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
- sig_size
;
255 ads
->ldap
.out
.sig_size
= sig_size
;
256 ads
->ldap
.in
.min_wrapped
= ads
->ldap
.out
.sig_size
;
257 ads
->ldap
.in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
258 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_ntlmssp_ops
, auth_generic_state
->gensec_security
);
259 if (!ADS_ERR_OK(status
)) {
260 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
261 ads_errstr(status
)));
262 TALLOC_FREE(auth_generic_state
);
265 /* Only keep the gensec_security element around long-term */
266 talloc_steal(NULL
, auth_generic_state
->gensec_security
);
268 TALLOC_FREE(auth_generic_state
);
270 return ADS_ERROR(rc
);
274 static ADS_STATUS
ads_init_gssapi_cred(ADS_STRUCT
*ads
, gss_cred_id_t
*cred
)
278 krb5_error_code kerr
;
279 krb5_ccache kccache
= NULL
;
282 *cred
= GSS_C_NO_CREDENTIAL
;
284 if (!ads
->auth
.ccache_name
) {
288 kerr
= krb5_init_context(&kctx
);
290 return ADS_ERROR_KRB5(kerr
);
293 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
294 kerr
= krb5_cc_resolve(kctx
, ads
->auth
.ccache_name
, &kccache
);
296 status
= ADS_ERROR_KRB5(kerr
);
300 maj
= gss_krb5_import_cred(&min
, kccache
, NULL
, NULL
, cred
);
301 if (maj
!= GSS_S_COMPLETE
) {
302 status
= ADS_ERROR_GSS(maj
, min
);
306 /* We need to fallback to overriding the default creds.
307 * This operation is not thread safe as it changes the process
308 * environment variable, but we do not have any better option
309 * with older kerberos libraries */
311 const char *oldccname
= NULL
;
313 oldccname
= getenv("KRB5CCNAME");
314 setenv("KRB5CCNAME", ads
->auth
.ccache_name
, 1);
316 maj
= gss_acquire_cred(&min
, GSS_C_NO_NAME
, GSS_C_INDEFINITE
,
317 NULL
, GSS_C_INITIATE
, cred
, NULL
, NULL
);
320 setenv("KRB5CCNAME", oldccname
, 1);
322 unsetenv("KRB5CCNAME");
325 if (maj
!= GSS_S_COMPLETE
) {
326 status
= ADS_ERROR_GSS(maj
, min
);
332 status
= ADS_SUCCESS
;
335 if (!ADS_ERR_OK(status
) && kccache
!= NULL
) {
336 krb5_cc_close(kctx
, kccache
);
338 krb5_free_context(kctx
);
342 static ADS_STATUS
ads_sasl_gssapi_wrap(ADS_STRUCT
*ads
, uint8
*buf
, uint32 len
)
344 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
348 gss_buffer_desc unwrapped
, wrapped
;
349 int conf_req_flag
, conf_state
;
351 unwrapped
.value
= buf
;
352 unwrapped
.length
= len
;
354 /* for now request sign and seal */
355 conf_req_flag
= (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
);
357 gss_rc
= gss_wrap(&minor_status
, context_handle
,
358 conf_req_flag
, GSS_C_QOP_DEFAULT
,
359 &unwrapped
, &conf_state
,
361 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
362 if (!ADS_ERR_OK(status
)) return status
;
364 if (conf_req_flag
&& conf_state
== 0) {
365 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
368 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
369 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
372 /* copy the wrapped blob to the right location */
373 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.value
, wrapped
.length
);
375 /* set how many bytes must be written to the underlying socket */
376 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
378 gss_release_buffer(&minor_status
, &wrapped
);
383 static ADS_STATUS
ads_sasl_gssapi_unwrap(ADS_STRUCT
*ads
)
385 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
389 gss_buffer_desc unwrapped
, wrapped
;
392 wrapped
.value
= ads
->ldap
.in
.buf
+ 4;
393 wrapped
.length
= ads
->ldap
.in
.ofs
- 4;
395 gss_rc
= gss_unwrap(&minor_status
, context_handle
,
396 &wrapped
, &unwrapped
,
397 &conf_state
, GSS_C_QOP_DEFAULT
);
398 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
399 if (!ADS_ERR_OK(status
)) return status
;
401 if (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
&& conf_state
== 0) {
402 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
405 if (wrapped
.length
< unwrapped
.length
) {
406 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
409 /* copy the wrapped blob to the right location */
410 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.value
, unwrapped
.length
);
412 /* set how many bytes must be written to the underlying socket */
413 ads
->ldap
.in
.left
= unwrapped
.length
;
414 ads
->ldap
.in
.ofs
= 4;
416 gss_release_buffer(&minor_status
, &unwrapped
);
421 static void ads_sasl_gssapi_disconnect(ADS_STRUCT
*ads
)
423 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
426 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
428 ads
->ldap
.wrap_ops
= NULL
;
429 ads
->ldap
.wrap_private_data
= NULL
;
432 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops
= {
434 .wrap
= ads_sasl_gssapi_wrap
,
435 .unwrap
= ads_sasl_gssapi_unwrap
,
436 .disconnect
= ads_sasl_gssapi_disconnect
440 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
442 static ADS_STATUS
ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
448 gss_cred_id_t gss_cred
= GSS_C_NO_CREDENTIAL
;
449 gss_OID_desc krb5_mech_type
=
450 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
451 gss_OID mech_type
= &krb5_mech_type
;
452 gss_OID actual_mech_type
= GSS_C_NULL_OID
;
453 const char *spnego_mechs
[] = {OID_KERBEROS5_OLD
, OID_KERBEROS5
, OID_NTLMSSP
, NULL
};
454 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
455 gss_buffer_desc input_token
, output_token
;
456 uint32 req_flags
, ret_flags
;
457 uint32 req_tmp
, ret_tmp
;
460 struct berval cred
, *scred
= NULL
;
462 status
= ads_init_gssapi_cred(ads
, &gss_cred
);
463 if (!ADS_ERR_OK(status
)) {
467 input_token
.value
= NULL
;
468 input_token
.length
= 0;
470 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
;
471 switch (ads
->ldap
.wrap_type
) {
472 case ADS_SASLWRAP_TYPE_SEAL
:
473 req_flags
|= GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
475 case ADS_SASLWRAP_TYPE_SIGN
:
476 req_flags
|= GSS_C_INTEG_FLAG
;
478 case ADS_SASLWRAP_TYPE_PLAIN
:
482 /* Note: here we explicit ask for the krb5 mech_type */
483 gss_rc
= gss_init_sec_context(&minor_status
,
496 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
497 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
502 * As some gssapi krb5 mech implementations
503 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
504 * to req_flags internaly, it's not possible to
505 * use plain or signing only connection via
506 * the gssapi interface.
508 * Because of this we need to check it the ret_flags
509 * has more flags as req_flags and correct the value
510 * of ads->ldap.wrap_type.
512 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
513 * we need to give an error.
515 req_tmp
= req_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
516 ret_tmp
= ret_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
518 if (req_tmp
== ret_tmp
) {
519 /* everythings fine... */
521 } else if (req_flags
& GSS_C_CONF_FLAG
) {
523 * here we wanted sealing but didn't got it
524 * from the gssapi library
526 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
529 } else if ((req_flags
& GSS_C_INTEG_FLAG
) &&
530 !(ret_flags
& GSS_C_INTEG_FLAG
)) {
532 * here we wanted siging but didn't got it
533 * from the gssapi library
535 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
538 } else if (ret_flags
& GSS_C_CONF_FLAG
) {
540 * here we didn't want sealing
541 * but the gssapi library forces it
542 * so correct the needed wrap_type if
543 * the caller didn't forced siging only
545 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
546 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
550 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
551 req_flags
= ret_flags
;
553 } else if (ret_flags
& GSS_C_INTEG_FLAG
) {
555 * here we didn't want signing
556 * but the gssapi library forces it
557 * so correct the needed wrap_type if
558 * the caller didn't forced plain
560 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
561 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
565 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
566 req_flags
= ret_flags
;
569 * This could (should?) not happen
571 status
= ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
576 /* and wrap that in a shiny SPNEGO wrapper */
577 unwrapped
= data_blob_const(output_token
.value
, output_token
.length
);
578 wrapped
= spnego_gen_negTokenInit(talloc_tos(),
579 spnego_mechs
, &unwrapped
, NULL
);
580 gss_release_buffer(&minor_status
, &output_token
);
581 if (unwrapped
.length
> wrapped
.length
) {
582 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
586 cred
.bv_val
= (char *)wrapped
.data
;
587 cred
.bv_len
= wrapped
.length
;
589 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
,
591 data_blob_free(&wrapped
);
592 if (rc
!= LDAP_SUCCESS
) {
593 status
= ADS_ERROR(rc
);
598 wrapped
= data_blob_const(scred
->bv_val
, scred
->bv_len
);
600 wrapped
= data_blob_null
;
603 ok
= spnego_parse_auth_response(talloc_tos(), wrapped
, NT_STATUS_OK
,
606 if (scred
) ber_bvfree(scred
);
608 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
612 input_token
.value
= unwrapped
.data
;
613 input_token
.length
= unwrapped
.length
;
616 * As we asked for mutal authentication
617 * we need to pass the servers response
620 gss_rc
= gss_init_sec_context(&minor_status
,
633 data_blob_free(&unwrapped
);
635 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
639 gss_release_buffer(&minor_status
, &output_token
);
642 * If we the sign and seal options
643 * doesn't match after getting the response
644 * from the server, we don't want to use the connection
646 req_tmp
= req_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
647 ret_tmp
= ret_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
649 if (req_tmp
!= ret_tmp
) {
650 /* everythings fine... */
651 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
655 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
656 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
658 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
659 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
661 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
663 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
667 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
668 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
669 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
670 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
671 if (!ADS_ERR_OK(status
)) {
672 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
673 ads_errstr(status
)));
676 /* make sure we don't free context_handle */
677 context_handle
= GSS_C_NO_CONTEXT
;
680 status
= ADS_SUCCESS
;
683 if (gss_cred
!= GSS_C_NO_CREDENTIAL
)
684 gss_release_cred(&minor_status
, &gss_cred
);
685 if (context_handle
!= GSS_C_NO_CONTEXT
)
686 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
690 #endif /* HAVE_KRB5 */
693 struct ads_service_principal
{
700 static void ads_free_service_principal(struct ads_service_principal
*p
)
702 SAFE_FREE(p
->string
);
707 gss_release_name(&minor_status
, &p
->name
);
714 static ADS_STATUS
ads_guess_service_principal(ADS_STRUCT
*ads
,
715 char **returned_principal
)
717 ADS_STATUS status
= ADS_ERROR(LDAP_NO_MEMORY
);
724 frame
= talloc_stackframe();
726 return ADS_ERROR(LDAP_NO_MEMORY
);
729 if (ads
->server
.realm
&& ads
->server
.ldap_server
) {
730 server
= strlower_talloc(frame
, ads
->server
.ldap_server
);
731 if (server
== NULL
) {
735 realm
= strupper_talloc(frame
, ads
->server
.realm
);
741 * If we got a name which is bigger than a NetBIOS name,
742 * but isn't a FQDN, create one.
744 if (strlen(server
) > 15 && strstr(server
, ".") == NULL
) {
747 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
748 if (dnsdomain
== NULL
) {
752 server
= talloc_asprintf(frame
,
755 if (server
== NULL
) {
759 } else if (ads
->config
.realm
&& ads
->config
.ldap_server_name
) {
760 server
= strlower_talloc(frame
, ads
->config
.ldap_server_name
);
761 if (server
== NULL
) {
765 realm
= strupper_talloc(frame
, ads
->config
.realm
);
771 * If we got a name which is bigger than a NetBIOS name,
772 * but isn't a FQDN, create one.
774 if (strlen(server
) > 15 && strstr(server
, ".") == NULL
) {
777 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
778 if (dnsdomain
== NULL
) {
782 server
= talloc_asprintf(frame
,
785 if (server
== NULL
) {
791 if (server
== NULL
|| realm
== NULL
) {
795 rc
= asprintf(&princ
, "ldap/%s@%s", server
, realm
);
796 if (rc
== -1 || princ
== NULL
) {
797 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
801 *returned_principal
= princ
;
803 status
= ADS_SUCCESS
;
809 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
810 const char *given_principal
,
811 struct ads_service_principal
*p
)
815 gss_buffer_desc input_name
;
816 /* GSS_KRB5_NT_PRINCIPAL_NAME */
817 gss_OID_desc nt_principal
=
818 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
825 /* I've seen a child Windows 2000 domain not send
826 the principal name back in the first round of
827 the SASL bind reply. So we guess based on server
828 name and realm. --jerry */
829 /* Also try best guess when we get the w2k8 ignore principal
830 back, or when we are configured to ignore it - gd,
833 if (!lp_client_use_spnego_principal() ||
835 strequal(given_principal
, ADS_IGNORE_PRINCIPAL
)) {
837 status
= ads_guess_service_principal(ads
, &p
->string
);
838 if (!ADS_ERR_OK(status
)) {
842 p
->string
= SMB_STRDUP(given_principal
);
844 return ADS_ERROR(LDAP_NO_MEMORY
);
849 input_name
.value
= p
->string
;
850 input_name
.length
= strlen(p
->string
);
852 gss_rc
= gss_import_name(&minor_status
, &input_name
, &nt_principal
, &p
->name
);
854 ads_free_service_principal(p
);
855 return ADS_ERROR_GSS(gss_rc
, minor_status
);
863 perform a LDAP/SASL/SPNEGO/KRB5 bind
865 static ADS_STATUS
ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT
*ads
, const char *principal
)
867 DATA_BLOB blob
= data_blob_null
;
868 struct berval cred
, *scred
= NULL
;
869 DATA_BLOB session_key
= data_blob_null
;
872 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
873 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
876 rc
= spnego_gen_krb5_negTokenInit(talloc_tos(), principal
,
877 ads
->auth
.time_offset
, &blob
, &session_key
, 0,
878 ads
->auth
.ccache_name
,
879 &ads
->auth
.tgs_expire
);
882 return ADS_ERROR_KRB5(rc
);
885 /* now send the auth packet and we should be done */
886 cred
.bv_val
= (char *)blob
.data
;
887 cred
.bv_len
= blob
.length
;
889 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
, &scred
);
891 data_blob_free(&blob
);
892 data_blob_free(&session_key
);
896 return ADS_ERROR(rc
);
899 static ADS_STATUS
ads_sasl_spnego_krb5_bind(ADS_STRUCT
*ads
,
900 struct ads_service_principal
*p
)
904 * we only use the gsskrb5 based implementation
905 * when sasl sign or seal is requested.
907 * This has the following reasons:
908 * - it's likely that the gssapi krb5 mech implementation
909 * doesn't support to negotiate plain connections
910 * - the ads_sasl_spnego_rawkrb5_bind is more robust
911 * against clock skew errors
913 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
914 return ads_sasl_spnego_gsskrb5_bind(ads
, p
->name
);
917 return ads_sasl_spnego_rawkrb5_bind(ads
, p
->string
);
919 #endif /* HAVE_KRB5 */
922 this performs a SASL/SPNEGO bind
924 static ADS_STATUS
ads_sasl_spnego_bind(ADS_STRUCT
*ads
)
926 struct berval
*scred
=NULL
;
930 char *given_principal
= NULL
;
931 char *OIDs
[ASN1_MAX_OIDS
];
933 bool got_kerberos_mechanism
= False
;
936 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", NULL
, NULL
, NULL
, &scred
);
938 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
939 status
= ADS_ERROR(rc
);
943 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
948 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
951 /* the server sent us the first part of the SPNEGO exchange in the negprot
953 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
955 data_blob_free(&blob
);
956 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
959 data_blob_free(&blob
);
961 /* make sure the server understands kerberos */
962 for (i
=0;OIDs
[i
];i
++) {
963 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs
[i
]));
965 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
966 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
967 got_kerberos_mechanism
= True
;
970 talloc_free(OIDs
[i
]);
972 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal
));
975 if (!(ads
->auth
.flags
& ADS_AUTH_DISABLE_KERBEROS
) &&
976 got_kerberos_mechanism
)
978 struct ads_service_principal p
;
980 status
= ads_generate_service_principal(ads
, given_principal
, &p
);
981 TALLOC_FREE(given_principal
);
982 if (!ADS_ERR_OK(status
)) {
986 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
987 if (ADS_ERR_OK(status
)) {
988 ads_free_service_principal(&p
);
992 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
993 "calling kinit\n", ads_errstr(status
)));
995 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
997 if (ADS_ERR_OK(status
)) {
998 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
999 if (!ADS_ERR_OK(status
)) {
1000 DEBUG(0,("kinit succeeded but "
1001 "ads_sasl_spnego_krb5_bind failed: %s\n",
1002 ads_errstr(status
)));
1006 ads_free_service_principal(&p
);
1008 /* only fallback to NTLMSSP if allowed */
1009 if (ADS_ERR_OK(status
) ||
1010 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
1016 TALLOC_FREE(given_principal
);
1019 /* lets do NTLMSSP ... this has the big advantage that we don't need
1020 to sync clocks, and we don't rely on special versions of the krb5
1021 library for HMAC_MD4 encryption */
1022 return ads_sasl_spnego_ntlmssp_bind(ads
);
1029 #define MAX_GSS_PASSES 3
1031 /* this performs a SASL/gssapi bind
1032 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
1033 is very dependent on correctly configured DNS whereas
1034 this routine is much less fragile
1035 see RFC2078 and RFC2222 for details
1037 static ADS_STATUS
ads_sasl_gssapi_do_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
1039 uint32 minor_status
;
1040 gss_cred_id_t gss_cred
= GSS_C_NO_CREDENTIAL
;
1041 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
1042 gss_OID mech_type
= GSS_C_NULL_OID
;
1043 gss_buffer_desc output_token
, input_token
;
1044 uint32 req_flags
, ret_flags
;
1047 struct berval
*scred
= NULL
;
1051 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
1052 uint8 wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1055 input_token
.value
= NULL
;
1056 input_token
.length
= 0;
1058 status
= ads_init_gssapi_cred(ads
, &gss_cred
);
1059 if (!ADS_ERR_OK(status
)) {
1064 * Note: here we always ask the gssapi for sign and seal
1065 * as this is negotiated later after the mutal
1068 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
| GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
1070 for (i
=0; i
< MAX_GSS_PASSES
; i
++) {
1071 gss_rc
= gss_init_sec_context(&minor_status
,
1088 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
1089 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1093 cred
.bv_val
= (char *)output_token
.value
;
1094 cred
.bv_len
= output_token
.length
;
1096 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
1098 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
1099 status
= ADS_ERROR(rc
);
1103 if (output_token
.value
) {
1104 gss_release_buffer(&minor_status
, &output_token
);
1108 input_token
.value
= scred
->bv_val
;
1109 input_token
.length
= scred
->bv_len
;
1111 input_token
.value
= NULL
;
1112 input_token
.length
= 0;
1115 if (gss_rc
== 0) break;
1118 gss_rc
= gss_unwrap(&minor_status
,context_handle
,&input_token
,&output_token
,
1125 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1129 p
= (uint8
*)output_token
.value
;
1132 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
1136 wrap_type
= CVAL(p
,0);
1138 max_msg_size
= RIVAL(p
,0);
1141 gss_release_buffer(&minor_status
, &output_token
);
1143 if (!(wrap_type
& ads
->ldap
.wrap_type
)) {
1145 * the server doesn't supports the wrap
1148 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1149 ads
->ldap
.wrap_type
, wrap_type
));
1150 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1151 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
1155 /* 0x58 is the minimum windows accepts */
1156 if (max_msg_size
< 0x58) {
1157 max_msg_size
= 0x58;
1160 output_token
.length
= 4;
1161 output_token
.value
= SMB_MALLOC(output_token
.length
);
1162 if (!output_token
.value
) {
1163 output_token
.length
= 0;
1164 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
1167 p
= (uint8
*)output_token
.value
;
1169 RSIVAL(p
,0,max_msg_size
);
1170 SCVAL(p
,0,ads
->ldap
.wrap_type
);
1173 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1174 * but using ads->config.bind_path is the wrong! It should be
1175 * the DN of the user object!
1177 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1178 * is ok and matches the information flow used in GSS-SPNEGO.
1181 gss_rc
= gss_wrap(&minor_status
, context_handle
,0,GSS_C_QOP_DEFAULT
,
1182 &output_token
, /* used as *input* here. */
1184 &input_token
); /* Used as *output* here. */
1186 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1187 output_token
.length
= 0;
1188 SAFE_FREE(output_token
.value
);
1192 /* We've finished with output_token. */
1193 SAFE_FREE(output_token
.value
);
1194 output_token
.length
= 0;
1196 cred
.bv_val
= (char *)input_token
.value
;
1197 cred
.bv_len
= input_token
.length
;
1199 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
1201 gss_release_buffer(&minor_status
, &input_token
);
1202 status
= ADS_ERROR(rc
);
1203 if (!ADS_ERR_OK(status
)) {
1207 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
1208 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
1209 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
1211 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
1213 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1217 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
1218 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
1219 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
1220 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
1221 if (!ADS_ERR_OK(status
)) {
1222 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1223 ads_errstr(status
)));
1226 /* make sure we don't free context_handle */
1227 context_handle
= GSS_C_NO_CONTEXT
;
1231 if (gss_cred
!= GSS_C_NO_CREDENTIAL
)
1232 gss_release_cred(&minor_status
, &gss_cred
);
1233 if (context_handle
!= GSS_C_NO_CONTEXT
)
1234 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
1241 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1244 struct ads_service_principal p
;
1246 status
= ads_generate_service_principal(ads
, NULL
, &p
);
1247 if (!ADS_ERR_OK(status
)) {
1251 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1252 if (ADS_ERR_OK(status
)) {
1253 ads_free_service_principal(&p
);
1257 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1258 "calling kinit\n", ads_errstr(status
)));
1260 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
1262 if (ADS_ERR_OK(status
)) {
1263 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1266 ads_free_service_principal(&p
);
1271 #endif /* HAVE_KRB5 */
1273 /* mapping between SASL mechanisms and functions */
1276 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1277 } sasl_mechanisms
[] = {
1278 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1280 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1285 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1287 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
1293 /* get a list of supported SASL mechanisms */
1294 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
1295 if (!ADS_ERR_OK(status
)) return status
;
1297 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
1299 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
1300 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
1301 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
1302 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1304 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1307 /* try our supported mechanisms in order */
1308 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
1309 /* see if the server supports it */
1310 for (j
=0;values
&& values
[j
];j
++) {
1311 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
1312 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
1314 status
= sasl_mechanisms
[i
].fn(ads
);
1315 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
1316 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
1317 ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
1319 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1320 "retrying with signing enabled\n"));
1321 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1324 ldap_value_free(values
);
1331 ldap_value_free(values
);
1333 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1336 #endif /* HAVE_LDAP */