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