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
)
719 if (ads
->server
.realm
&& ads
->server
.ldap_server
) {
720 char *server
, *server_realm
;
722 server
= SMB_STRDUP(ads
->server
.ldap_server
);
723 server_realm
= SMB_STRDUP(ads
->server
.realm
);
725 if (!server
|| !server_realm
) {
727 SAFE_FREE(server_realm
);
728 return ADS_ERROR(LDAP_NO_MEMORY
);
731 if (!strlower_m(server
)) {
733 SAFE_FREE(server_realm
);
734 return ADS_ERROR(LDAP_NO_MEMORY
);
737 if (!strupper_m(server_realm
)) {
739 SAFE_FREE(server_realm
);
740 return ADS_ERROR(LDAP_NO_MEMORY
);
743 if (asprintf(&princ
, "ldap/%s@%s", server
, server_realm
) == -1) {
745 SAFE_FREE(server_realm
);
746 return ADS_ERROR(LDAP_NO_MEMORY
);
750 SAFE_FREE(server_realm
);
753 return ADS_ERROR(LDAP_NO_MEMORY
);
755 } else if (ads
->config
.realm
&& ads
->config
.ldap_server_name
) {
756 char *server
, *server_realm
;
758 server
= SMB_STRDUP(ads
->config
.ldap_server_name
);
759 server_realm
= SMB_STRDUP(ads
->config
.realm
);
761 if (!server
|| !server_realm
) {
763 SAFE_FREE(server_realm
);
764 return ADS_ERROR(LDAP_NO_MEMORY
);
767 if (!strlower_m(server
)) {
769 SAFE_FREE(server_realm
);
770 return ADS_ERROR(LDAP_NO_MEMORY
);
773 if (!strupper_m(server_realm
)) {
775 SAFE_FREE(server_realm
);
776 return ADS_ERROR(LDAP_NO_MEMORY
);
778 if (asprintf(&princ
, "ldap/%s@%s", server
, server_realm
) == -1) {
780 SAFE_FREE(server_realm
);
781 return ADS_ERROR(LDAP_NO_MEMORY
);
785 SAFE_FREE(server_realm
);
788 return ADS_ERROR(LDAP_NO_MEMORY
);
793 return ADS_ERROR(LDAP_PARAM_ERROR
);
796 *returned_principal
= princ
;
801 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
802 const char *given_principal
,
803 struct ads_service_principal
*p
)
807 gss_buffer_desc input_name
;
808 /* GSS_KRB5_NT_PRINCIPAL_NAME */
809 gss_OID_desc nt_principal
=
810 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
817 /* I've seen a child Windows 2000 domain not send
818 the principal name back in the first round of
819 the SASL bind reply. So we guess based on server
820 name and realm. --jerry */
821 /* Also try best guess when we get the w2k8 ignore principal
822 back, or when we are configured to ignore it - gd,
825 if (!lp_client_use_spnego_principal() ||
827 strequal(given_principal
, ADS_IGNORE_PRINCIPAL
)) {
829 status
= ads_guess_service_principal(ads
, &p
->string
);
830 if (!ADS_ERR_OK(status
)) {
834 p
->string
= SMB_STRDUP(given_principal
);
836 return ADS_ERROR(LDAP_NO_MEMORY
);
841 input_name
.value
= p
->string
;
842 input_name
.length
= strlen(p
->string
);
844 gss_rc
= gss_import_name(&minor_status
, &input_name
, &nt_principal
, &p
->name
);
846 ads_free_service_principal(p
);
847 return ADS_ERROR_GSS(gss_rc
, minor_status
);
855 perform a LDAP/SASL/SPNEGO/KRB5 bind
857 static ADS_STATUS
ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT
*ads
, const char *principal
)
859 DATA_BLOB blob
= data_blob_null
;
860 struct berval cred
, *scred
= NULL
;
861 DATA_BLOB session_key
= data_blob_null
;
864 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
865 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
868 rc
= spnego_gen_krb5_negTokenInit(talloc_tos(), principal
,
869 ads
->auth
.time_offset
, &blob
, &session_key
, 0,
870 ads
->auth
.ccache_name
,
871 &ads
->auth
.tgs_expire
);
874 return ADS_ERROR_KRB5(rc
);
877 /* now send the auth packet and we should be done */
878 cred
.bv_val
= (char *)blob
.data
;
879 cred
.bv_len
= blob
.length
;
881 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
, &scred
);
883 data_blob_free(&blob
);
884 data_blob_free(&session_key
);
888 return ADS_ERROR(rc
);
891 static ADS_STATUS
ads_sasl_spnego_krb5_bind(ADS_STRUCT
*ads
,
892 struct ads_service_principal
*p
)
896 * we only use the gsskrb5 based implementation
897 * when sasl sign or seal is requested.
899 * This has the following reasons:
900 * - it's likely that the gssapi krb5 mech implementation
901 * doesn't support to negotiate plain connections
902 * - the ads_sasl_spnego_rawkrb5_bind is more robust
903 * against clock skew errors
905 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
906 return ads_sasl_spnego_gsskrb5_bind(ads
, p
->name
);
909 return ads_sasl_spnego_rawkrb5_bind(ads
, p
->string
);
911 #endif /* HAVE_KRB5 */
914 this performs a SASL/SPNEGO bind
916 static ADS_STATUS
ads_sasl_spnego_bind(ADS_STRUCT
*ads
)
918 struct berval
*scred
=NULL
;
922 char *given_principal
= NULL
;
923 char *OIDs
[ASN1_MAX_OIDS
];
925 bool got_kerberos_mechanism
= False
;
928 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", NULL
, NULL
, NULL
, &scred
);
930 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
931 status
= ADS_ERROR(rc
);
935 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
940 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
943 /* the server sent us the first part of the SPNEGO exchange in the negprot
945 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
947 data_blob_free(&blob
);
948 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
951 data_blob_free(&blob
);
953 /* make sure the server understands kerberos */
954 for (i
=0;OIDs
[i
];i
++) {
955 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs
[i
]));
957 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
958 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
959 got_kerberos_mechanism
= True
;
962 talloc_free(OIDs
[i
]);
964 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal
));
967 if (!(ads
->auth
.flags
& ADS_AUTH_DISABLE_KERBEROS
) &&
968 got_kerberos_mechanism
)
970 struct ads_service_principal p
;
972 status
= ads_generate_service_principal(ads
, given_principal
, &p
);
973 TALLOC_FREE(given_principal
);
974 if (!ADS_ERR_OK(status
)) {
978 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
979 if (ADS_ERR_OK(status
)) {
980 ads_free_service_principal(&p
);
984 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
985 "calling kinit\n", ads_errstr(status
)));
987 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
989 if (ADS_ERR_OK(status
)) {
990 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
991 if (!ADS_ERR_OK(status
)) {
992 DEBUG(0,("kinit succeeded but "
993 "ads_sasl_spnego_krb5_bind failed: %s\n",
994 ads_errstr(status
)));
998 ads_free_service_principal(&p
);
1000 /* only fallback to NTLMSSP if allowed */
1001 if (ADS_ERR_OK(status
) ||
1002 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
1008 TALLOC_FREE(given_principal
);
1011 /* lets do NTLMSSP ... this has the big advantage that we don't need
1012 to sync clocks, and we don't rely on special versions of the krb5
1013 library for HMAC_MD4 encryption */
1014 return ads_sasl_spnego_ntlmssp_bind(ads
);
1021 #define MAX_GSS_PASSES 3
1023 /* this performs a SASL/gssapi bind
1024 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
1025 is very dependent on correctly configured DNS whereas
1026 this routine is much less fragile
1027 see RFC2078 and RFC2222 for details
1029 static ADS_STATUS
ads_sasl_gssapi_do_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
1031 uint32 minor_status
;
1032 gss_cred_id_t gss_cred
= GSS_C_NO_CREDENTIAL
;
1033 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
1034 gss_OID mech_type
= GSS_C_NULL_OID
;
1035 gss_buffer_desc output_token
, input_token
;
1036 uint32 req_flags
, ret_flags
;
1039 struct berval
*scred
= NULL
;
1043 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
1044 uint8 wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1047 input_token
.value
= NULL
;
1048 input_token
.length
= 0;
1050 status
= ads_init_gssapi_cred(ads
, &gss_cred
);
1051 if (!ADS_ERR_OK(status
)) {
1056 * Note: here we always ask the gssapi for sign and seal
1057 * as this is negotiated later after the mutal
1060 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
| GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
1062 for (i
=0; i
< MAX_GSS_PASSES
; i
++) {
1063 gss_rc
= gss_init_sec_context(&minor_status
,
1080 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
1081 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1085 cred
.bv_val
= (char *)output_token
.value
;
1086 cred
.bv_len
= output_token
.length
;
1088 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
1090 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
1091 status
= ADS_ERROR(rc
);
1095 if (output_token
.value
) {
1096 gss_release_buffer(&minor_status
, &output_token
);
1100 input_token
.value
= scred
->bv_val
;
1101 input_token
.length
= scred
->bv_len
;
1103 input_token
.value
= NULL
;
1104 input_token
.length
= 0;
1107 if (gss_rc
== 0) break;
1110 gss_rc
= gss_unwrap(&minor_status
,context_handle
,&input_token
,&output_token
,
1117 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1121 p
= (uint8
*)output_token
.value
;
1124 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
1128 wrap_type
= CVAL(p
,0);
1130 max_msg_size
= RIVAL(p
,0);
1133 gss_release_buffer(&minor_status
, &output_token
);
1135 if (!(wrap_type
& ads
->ldap
.wrap_type
)) {
1137 * the server doesn't supports the wrap
1140 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1141 ads
->ldap
.wrap_type
, wrap_type
));
1142 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1143 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
1147 /* 0x58 is the minimum windows accepts */
1148 if (max_msg_size
< 0x58) {
1149 max_msg_size
= 0x58;
1152 output_token
.length
= 4;
1153 output_token
.value
= SMB_MALLOC(output_token
.length
);
1154 if (!output_token
.value
) {
1155 output_token
.length
= 0;
1156 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
1159 p
= (uint8
*)output_token
.value
;
1161 RSIVAL(p
,0,max_msg_size
);
1162 SCVAL(p
,0,ads
->ldap
.wrap_type
);
1165 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1166 * but using ads->config.bind_path is the wrong! It should be
1167 * the DN of the user object!
1169 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1170 * is ok and matches the information flow used in GSS-SPNEGO.
1173 gss_rc
= gss_wrap(&minor_status
, context_handle
,0,GSS_C_QOP_DEFAULT
,
1174 &output_token
, /* used as *input* here. */
1176 &input_token
); /* Used as *output* here. */
1178 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1179 output_token
.length
= 0;
1180 SAFE_FREE(output_token
.value
);
1184 /* We've finished with output_token. */
1185 SAFE_FREE(output_token
.value
);
1186 output_token
.length
= 0;
1188 cred
.bv_val
= (char *)input_token
.value
;
1189 cred
.bv_len
= input_token
.length
;
1191 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
1193 gss_release_buffer(&minor_status
, &input_token
);
1194 status
= ADS_ERROR(rc
);
1195 if (!ADS_ERR_OK(status
)) {
1199 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
1200 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
1201 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
1203 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
1205 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1209 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
1210 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
1211 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
1212 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
1213 if (!ADS_ERR_OK(status
)) {
1214 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1215 ads_errstr(status
)));
1218 /* make sure we don't free context_handle */
1219 context_handle
= GSS_C_NO_CONTEXT
;
1223 if (gss_cred
!= GSS_C_NO_CREDENTIAL
)
1224 gss_release_cred(&minor_status
, &gss_cred
);
1225 if (context_handle
!= GSS_C_NO_CONTEXT
)
1226 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
1233 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1236 struct ads_service_principal p
;
1238 status
= ads_generate_service_principal(ads
, NULL
, &p
);
1239 if (!ADS_ERR_OK(status
)) {
1243 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1244 if (ADS_ERR_OK(status
)) {
1245 ads_free_service_principal(&p
);
1249 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1250 "calling kinit\n", ads_errstr(status
)));
1252 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
1254 if (ADS_ERR_OK(status
)) {
1255 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1258 ads_free_service_principal(&p
);
1263 #endif /* HAVE_KRB5 */
1265 /* mapping between SASL mechanisms and functions */
1268 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1269 } sasl_mechanisms
[] = {
1270 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1272 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1277 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1279 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
1285 /* get a list of supported SASL mechanisms */
1286 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
1287 if (!ADS_ERR_OK(status
)) return status
;
1289 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
1291 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
1292 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
1293 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
1294 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1296 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1299 /* try our supported mechanisms in order */
1300 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
1301 /* see if the server supports it */
1302 for (j
=0;values
&& values
[j
];j
++) {
1303 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
1304 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
1306 status
= sasl_mechanisms
[i
].fn(ads
);
1307 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
1308 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
1309 ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
1311 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1312 "retrying with signing enabled\n"));
1313 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1316 ldap_value_free(values
);
1323 ldap_value_free(values
);
1325 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1328 #endif /* HAVE_LDAP */