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"
30 static ADS_STATUS
ads_sasl_ntlmssp_wrap(ADS_STRUCT
*ads
, uint8
*buf
, uint32 len
)
32 struct gensec_security
*gensec_security
=
33 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
34 struct gensec_security
);
36 DATA_BLOB unwrapped
, wrapped
;
37 TALLOC_CTX
*frame
= talloc_stackframe();
39 unwrapped
= data_blob_const(buf
, len
);
41 nt_status
= gensec_wrap(gensec_security
, frame
, &unwrapped
, &wrapped
);
42 if (!NT_STATUS_IS_OK(nt_status
)) {
44 return ADS_ERROR_NT(nt_status
);
47 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
48 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
51 /* copy the wrapped blob to the right location */
52 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.data
, wrapped
.length
);
54 /* set how many bytes must be written to the underlying socket */
55 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
62 static ADS_STATUS
ads_sasl_ntlmssp_unwrap(ADS_STRUCT
*ads
)
64 struct gensec_security
*gensec_security
=
65 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
66 struct gensec_security
);
68 DATA_BLOB unwrapped
, wrapped
;
69 TALLOC_CTX
*frame
= talloc_stackframe();
71 wrapped
= data_blob_const(ads
->ldap
.in
.buf
+ 4, ads
->ldap
.in
.ofs
- 4);
73 nt_status
= gensec_unwrap(gensec_security
, frame
, &wrapped
, &unwrapped
);
74 if (!NT_STATUS_IS_OK(nt_status
)) {
76 return ADS_ERROR_NT(nt_status
);
79 if (wrapped
.length
< unwrapped
.length
) {
81 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
84 /* copy the wrapped blob to the right location */
85 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.data
, unwrapped
.length
);
87 /* set how many bytes must be written to the underlying socket */
88 ads
->ldap
.in
.left
= unwrapped
.length
;
96 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT
*ads
)
98 struct gensec_security
*gensec_security
=
99 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
100 struct gensec_security
);
102 TALLOC_FREE(gensec_security
);
104 ads
->ldap
.wrap_ops
= NULL
;
105 ads
->ldap
.wrap_private_data
= NULL
;
108 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops
= {
110 .wrap
= ads_sasl_ntlmssp_wrap
,
111 .unwrap
= ads_sasl_ntlmssp_unwrap
,
112 .disconnect
= ads_sasl_ntlmssp_disconnect
116 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
117 we fit on one socket??)
119 static ADS_STATUS
ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT
*ads
)
121 DATA_BLOB msg1
= data_blob_null
;
122 DATA_BLOB blob
= data_blob_null
;
123 DATA_BLOB blob_in
= data_blob_null
;
124 DATA_BLOB blob_out
= data_blob_null
;
125 struct berval cred
, *scred
= NULL
;
131 struct auth_generic_state
*auth_generic_state
;
133 nt_status
= auth_generic_client_prepare(NULL
, &auth_generic_state
);
134 if (!NT_STATUS_IS_OK(nt_status
)) {
135 return ADS_ERROR_NT(nt_status
);
138 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_username(auth_generic_state
, ads
->auth
.user_name
))) {
139 return ADS_ERROR_NT(nt_status
);
141 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_domain(auth_generic_state
, ads
->auth
.realm
))) {
142 return ADS_ERROR_NT(nt_status
);
144 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_password(auth_generic_state
, ads
->auth
.password
))) {
145 return ADS_ERROR_NT(nt_status
);
148 switch (ads
->ldap
.wrap_type
) {
149 case ADS_SASLWRAP_TYPE_SEAL
:
150 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
151 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SEAL
);
153 case ADS_SASLWRAP_TYPE_SIGN
:
154 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
155 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
158 * windows servers are broken with sign only,
159 * so we need to use seal here too
161 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
162 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SEAL
);
163 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
166 case ADS_SASLWRAP_TYPE_PLAIN
:
170 nt_status
= auth_generic_client_start(auth_generic_state
, GENSEC_OID_NTLMSSP
);
171 if (!NT_STATUS_IS_OK(nt_status
)) {
172 return ADS_ERROR_NT(nt_status
);
175 blob_in
= data_blob_null
;
178 nt_status
= gensec_update(auth_generic_state
->gensec_security
,
179 talloc_tos(), NULL
, blob_in
, &blob_out
);
180 data_blob_free(&blob_in
);
181 if ((NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)
182 || NT_STATUS_IS_OK(nt_status
))
183 && blob_out
.length
) {
185 const char *OIDs_ntlm
[] = {OID_NTLMSSP
, NULL
};
186 /* and wrap it in a SPNEGO wrapper */
187 msg1
= spnego_gen_negTokenInit(talloc_tos(),
188 OIDs_ntlm
, &blob_out
, NULL
);
190 /* wrap it in SPNEGO */
191 msg1
= spnego_gen_auth(talloc_tos(), blob_out
);
194 data_blob_free(&blob_out
);
196 cred
.bv_val
= (char *)msg1
.data
;
197 cred
.bv_len
= msg1
.length
;
199 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
, &scred
);
200 data_blob_free(&msg1
);
201 if ((rc
!= LDAP_SASL_BIND_IN_PROGRESS
) && (rc
!= 0)) {
206 TALLOC_FREE(auth_generic_state
);
207 return ADS_ERROR(rc
);
210 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
213 blob
= data_blob_null
;
218 TALLOC_FREE(auth_generic_state
);
219 data_blob_free(&blob_out
);
220 return ADS_ERROR_NT(nt_status
);
224 (rc
== LDAP_SASL_BIND_IN_PROGRESS
)) {
225 DATA_BLOB tmp_blob
= data_blob_null
;
226 /* the server might give us back two challenges */
227 if (!spnego_parse_challenge(talloc_tos(), blob
, &blob_in
,
230 TALLOC_FREE(auth_generic_state
);
231 data_blob_free(&blob
);
232 DEBUG(3,("Failed to parse challenges\n"));
233 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
235 data_blob_free(&tmp_blob
);
236 } else if (rc
== LDAP_SASL_BIND_IN_PROGRESS
) {
237 if (!spnego_parse_auth_response(talloc_tos(), blob
, nt_status
, OID_NTLMSSP
,
240 TALLOC_FREE(auth_generic_state
);
241 data_blob_free(&blob
);
242 DEBUG(3,("Failed to parse auth response\n"));
243 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
246 data_blob_free(&blob
);
247 data_blob_free(&blob_out
);
249 } while (rc
== LDAP_SASL_BIND_IN_PROGRESS
&& !NT_STATUS_IS_OK(nt_status
));
251 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
252 uint32_t sig_size
= gensec_sig_size(auth_generic_state
->gensec_security
, 0);
253 ads
->ldap
.out
.max_unwrapped
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
- sig_size
;
254 ads
->ldap
.out
.sig_size
= sig_size
;
255 ads
->ldap
.in
.min_wrapped
= ads
->ldap
.out
.sig_size
;
256 ads
->ldap
.in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
257 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_ntlmssp_ops
, auth_generic_state
->gensec_security
);
258 if (!ADS_ERR_OK(status
)) {
259 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
260 ads_errstr(status
)));
261 TALLOC_FREE(auth_generic_state
);
264 /* Only keep the gensec_security element around long-term */
265 talloc_steal(NULL
, auth_generic_state
->gensec_security
);
267 TALLOC_FREE(auth_generic_state
);
269 return ADS_ERROR(rc
);
273 static ADS_STATUS
ads_sasl_gssapi_wrap(ADS_STRUCT
*ads
, uint8
*buf
, uint32 len
)
275 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
279 gss_buffer_desc unwrapped
, wrapped
;
280 int conf_req_flag
, conf_state
;
282 unwrapped
.value
= buf
;
283 unwrapped
.length
= len
;
285 /* for now request sign and seal */
286 conf_req_flag
= (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
);
288 gss_rc
= gss_wrap(&minor_status
, context_handle
,
289 conf_req_flag
, GSS_C_QOP_DEFAULT
,
290 &unwrapped
, &conf_state
,
292 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
293 if (!ADS_ERR_OK(status
)) return status
;
295 if (conf_req_flag
&& conf_state
== 0) {
296 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
299 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
300 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
303 /* copy the wrapped blob to the right location */
304 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.value
, wrapped
.length
);
306 /* set how many bytes must be written to the underlying socket */
307 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
309 gss_release_buffer(&minor_status
, &wrapped
);
314 static ADS_STATUS
ads_sasl_gssapi_unwrap(ADS_STRUCT
*ads
)
316 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
320 gss_buffer_desc unwrapped
, wrapped
;
323 wrapped
.value
= ads
->ldap
.in
.buf
+ 4;
324 wrapped
.length
= ads
->ldap
.in
.ofs
- 4;
326 gss_rc
= gss_unwrap(&minor_status
, context_handle
,
327 &wrapped
, &unwrapped
,
328 &conf_state
, GSS_C_QOP_DEFAULT
);
329 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
330 if (!ADS_ERR_OK(status
)) return status
;
332 if (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
&& conf_state
== 0) {
333 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
336 if (wrapped
.length
< unwrapped
.length
) {
337 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
340 /* copy the wrapped blob to the right location */
341 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.value
, unwrapped
.length
);
343 /* set how many bytes must be written to the underlying socket */
344 ads
->ldap
.in
.left
= unwrapped
.length
;
345 ads
->ldap
.in
.ofs
= 4;
347 gss_release_buffer(&minor_status
, &unwrapped
);
352 static void ads_sasl_gssapi_disconnect(ADS_STRUCT
*ads
)
354 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
357 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
359 ads
->ldap
.wrap_ops
= NULL
;
360 ads
->ldap
.wrap_private_data
= NULL
;
363 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops
= {
365 .wrap
= ads_sasl_gssapi_wrap
,
366 .unwrap
= ads_sasl_gssapi_unwrap
,
367 .disconnect
= ads_sasl_gssapi_disconnect
371 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
373 static ADS_STATUS
ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
379 gss_OID_desc krb5_mech_type
=
380 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
381 gss_OID mech_type
= &krb5_mech_type
;
382 gss_OID actual_mech_type
= GSS_C_NULL_OID
;
383 const char *spnego_mechs
[] = {OID_KERBEROS5_OLD
, OID_KERBEROS5
, OID_NTLMSSP
, NULL
};
384 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
385 gss_buffer_desc input_token
, output_token
;
386 uint32 req_flags
, ret_flags
;
387 uint32 req_tmp
, ret_tmp
;
390 struct berval cred
, *scred
= NULL
;
392 input_token
.value
= NULL
;
393 input_token
.length
= 0;
395 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
;
396 switch (ads
->ldap
.wrap_type
) {
397 case ADS_SASLWRAP_TYPE_SEAL
:
398 req_flags
|= GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
400 case ADS_SASLWRAP_TYPE_SIGN
:
401 req_flags
|= GSS_C_INTEG_FLAG
;
403 case ADS_SASLWRAP_TYPE_PLAIN
:
407 /* Note: here we explicit ask for the krb5 mech_type */
408 gss_rc
= gss_init_sec_context(&minor_status
,
421 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
422 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
427 * As some gssapi krb5 mech implementations
428 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
429 * to req_flags internaly, it's not possible to
430 * use plain or signing only connection via
431 * the gssapi interface.
433 * Because of this we need to check it the ret_flags
434 * has more flags as req_flags and correct the value
435 * of ads->ldap.wrap_type.
437 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
438 * we need to give an error.
440 req_tmp
= req_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
441 ret_tmp
= ret_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
443 if (req_tmp
== ret_tmp
) {
444 /* everythings fine... */
446 } else if (req_flags
& GSS_C_CONF_FLAG
) {
448 * here we wanted sealing but didn't got it
449 * from the gssapi library
451 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
454 } else if ((req_flags
& GSS_C_INTEG_FLAG
) &&
455 !(ret_flags
& GSS_C_INTEG_FLAG
)) {
457 * here we wanted siging but didn't got it
458 * from the gssapi library
460 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
463 } else if (ret_flags
& GSS_C_CONF_FLAG
) {
465 * here we didn't want sealing
466 * but the gssapi library forces it
467 * so correct the needed wrap_type if
468 * the caller didn't forced siging only
470 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
471 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
475 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
476 req_flags
= ret_flags
;
478 } else if (ret_flags
& GSS_C_INTEG_FLAG
) {
480 * here we didn't want signing
481 * but the gssapi library forces it
482 * so correct the needed wrap_type if
483 * the caller didn't forced plain
485 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
486 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
490 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
491 req_flags
= ret_flags
;
494 * This could (should?) not happen
496 status
= ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
501 /* and wrap that in a shiny SPNEGO wrapper */
502 unwrapped
= data_blob_const(output_token
.value
, output_token
.length
);
503 wrapped
= spnego_gen_negTokenInit(talloc_tos(),
504 spnego_mechs
, &unwrapped
, NULL
);
505 gss_release_buffer(&minor_status
, &output_token
);
506 if (unwrapped
.length
> wrapped
.length
) {
507 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
511 cred
.bv_val
= (char *)wrapped
.data
;
512 cred
.bv_len
= wrapped
.length
;
514 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
,
516 data_blob_free(&wrapped
);
517 if (rc
!= LDAP_SUCCESS
) {
518 status
= ADS_ERROR(rc
);
523 wrapped
= data_blob_const(scred
->bv_val
, scred
->bv_len
);
525 wrapped
= data_blob_null
;
528 ok
= spnego_parse_auth_response(talloc_tos(), wrapped
, NT_STATUS_OK
,
531 if (scred
) ber_bvfree(scred
);
533 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
537 input_token
.value
= unwrapped
.data
;
538 input_token
.length
= unwrapped
.length
;
541 * As we asked for mutal authentication
542 * we need to pass the servers response
545 gss_rc
= gss_init_sec_context(&minor_status
,
558 data_blob_free(&unwrapped
);
560 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
564 gss_release_buffer(&minor_status
, &output_token
);
567 * If we the sign and seal options
568 * doesn't match after getting the response
569 * from the server, we don't want to use the connection
571 req_tmp
= req_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
572 ret_tmp
= ret_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
574 if (req_tmp
!= ret_tmp
) {
575 /* everythings fine... */
576 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
580 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
581 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
583 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
584 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
586 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
588 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
592 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
593 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
594 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
595 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
596 if (!ADS_ERR_OK(status
)) {
597 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
598 ads_errstr(status
)));
601 /* make sure we don't free context_handle */
602 context_handle
= GSS_C_NO_CONTEXT
;
605 status
= ADS_SUCCESS
;
608 if (context_handle
!= GSS_C_NO_CONTEXT
)
609 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
613 #endif /* HAVE_KRB5 */
616 struct ads_service_principal
{
623 static void ads_free_service_principal(struct ads_service_principal
*p
)
625 SAFE_FREE(p
->string
);
630 gss_release_name(&minor_status
, &p
->name
);
637 static ADS_STATUS
ads_guess_service_principal(ADS_STRUCT
*ads
,
638 char **returned_principal
)
642 if (ads
->server
.realm
&& ads
->server
.ldap_server
) {
643 char *server
, *server_realm
;
645 server
= SMB_STRDUP(ads
->server
.ldap_server
);
646 server_realm
= SMB_STRDUP(ads
->server
.realm
);
648 if (!server
|| !server_realm
) {
650 SAFE_FREE(server_realm
);
651 return ADS_ERROR(LDAP_NO_MEMORY
);
655 strupper_m(server_realm
);
656 if (asprintf(&princ
, "ldap/%s@%s", server
, server_realm
) == -1) {
658 SAFE_FREE(server_realm
);
659 return ADS_ERROR(LDAP_NO_MEMORY
);
663 SAFE_FREE(server_realm
);
666 return ADS_ERROR(LDAP_NO_MEMORY
);
668 } else if (ads
->config
.realm
&& ads
->config
.ldap_server_name
) {
669 char *server
, *server_realm
;
671 server
= SMB_STRDUP(ads
->config
.ldap_server_name
);
672 server_realm
= SMB_STRDUP(ads
->config
.realm
);
674 if (!server
|| !server_realm
) {
676 SAFE_FREE(server_realm
);
677 return ADS_ERROR(LDAP_NO_MEMORY
);
681 strupper_m(server_realm
);
682 if (asprintf(&princ
, "ldap/%s@%s", server
, server_realm
) == -1) {
684 SAFE_FREE(server_realm
);
685 return ADS_ERROR(LDAP_NO_MEMORY
);
689 SAFE_FREE(server_realm
);
692 return ADS_ERROR(LDAP_NO_MEMORY
);
697 return ADS_ERROR(LDAP_PARAM_ERROR
);
700 *returned_principal
= princ
;
705 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
706 const char *given_principal
,
707 struct ads_service_principal
*p
)
711 gss_buffer_desc input_name
;
712 /* GSS_KRB5_NT_PRINCIPAL_NAME */
713 gss_OID_desc nt_principal
=
714 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
721 /* I've seen a child Windows 2000 domain not send
722 the principal name back in the first round of
723 the SASL bind reply. So we guess based on server
724 name and realm. --jerry */
725 /* Also try best guess when we get the w2k8 ignore principal
726 back, or when we are configured to ignore it - gd,
729 if (!lp_client_use_spnego_principal() ||
731 strequal(given_principal
, ADS_IGNORE_PRINCIPAL
)) {
733 status
= ads_guess_service_principal(ads
, &p
->string
);
734 if (!ADS_ERR_OK(status
)) {
738 p
->string
= SMB_STRDUP(given_principal
);
740 return ADS_ERROR(LDAP_NO_MEMORY
);
745 input_name
.value
= p
->string
;
746 input_name
.length
= strlen(p
->string
);
748 gss_rc
= gss_import_name(&minor_status
, &input_name
, &nt_principal
, &p
->name
);
750 ads_free_service_principal(p
);
751 return ADS_ERROR_GSS(gss_rc
, minor_status
);
759 perform a LDAP/SASL/SPNEGO/KRB5 bind
761 static ADS_STATUS
ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT
*ads
, const char *principal
)
763 DATA_BLOB blob
= data_blob_null
;
764 struct berval cred
, *scred
= NULL
;
765 DATA_BLOB session_key
= data_blob_null
;
768 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
769 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
772 rc
= spnego_gen_krb5_negTokenInit(talloc_tos(), principal
,
773 ads
->auth
.time_offset
, &blob
, &session_key
, 0,
774 &ads
->auth
.tgs_expire
);
777 return ADS_ERROR_KRB5(rc
);
780 /* now send the auth packet and we should be done */
781 cred
.bv_val
= (char *)blob
.data
;
782 cred
.bv_len
= blob
.length
;
784 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
, &scred
);
786 data_blob_free(&blob
);
787 data_blob_free(&session_key
);
791 return ADS_ERROR(rc
);
794 static ADS_STATUS
ads_sasl_spnego_krb5_bind(ADS_STRUCT
*ads
,
795 struct ads_service_principal
*p
)
799 * we only use the gsskrb5 based implementation
800 * when sasl sign or seal is requested.
802 * This has the following reasons:
803 * - it's likely that the gssapi krb5 mech implementation
804 * doesn't support to negotiate plain connections
805 * - the ads_sasl_spnego_rawkrb5_bind is more robust
806 * against clock skew errors
808 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
809 return ads_sasl_spnego_gsskrb5_bind(ads
, p
->name
);
812 return ads_sasl_spnego_rawkrb5_bind(ads
, p
->string
);
814 #endif /* HAVE_KRB5 */
817 this performs a SASL/SPNEGO bind
819 static ADS_STATUS
ads_sasl_spnego_bind(ADS_STRUCT
*ads
)
821 struct berval
*scred
=NULL
;
825 char *given_principal
= NULL
;
826 char *OIDs
[ASN1_MAX_OIDS
];
828 bool got_kerberos_mechanism
= False
;
831 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", NULL
, NULL
, NULL
, &scred
);
833 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
834 status
= ADS_ERROR(rc
);
838 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
843 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
846 /* the server sent us the first part of the SPNEGO exchange in the negprot
848 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
850 data_blob_free(&blob
);
851 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
854 data_blob_free(&blob
);
856 /* make sure the server understands kerberos */
857 for (i
=0;OIDs
[i
];i
++) {
858 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs
[i
]));
860 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
861 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
862 got_kerberos_mechanism
= True
;
865 talloc_free(OIDs
[i
]);
867 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal
));
870 if (!(ads
->auth
.flags
& ADS_AUTH_DISABLE_KERBEROS
) &&
871 got_kerberos_mechanism
)
873 struct ads_service_principal p
;
875 status
= ads_generate_service_principal(ads
, given_principal
, &p
);
876 TALLOC_FREE(given_principal
);
877 if (!ADS_ERR_OK(status
)) {
881 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
882 if (ADS_ERR_OK(status
)) {
883 ads_free_service_principal(&p
);
887 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
888 "calling kinit\n", ads_errstr(status
)));
890 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
892 if (ADS_ERR_OK(status
)) {
893 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
894 if (!ADS_ERR_OK(status
)) {
895 DEBUG(0,("kinit succeeded but "
896 "ads_sasl_spnego_krb5_bind failed: %s\n",
897 ads_errstr(status
)));
901 ads_free_service_principal(&p
);
903 /* only fallback to NTLMSSP if allowed */
904 if (ADS_ERR_OK(status
) ||
905 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
911 TALLOC_FREE(given_principal
);
914 /* lets do NTLMSSP ... this has the big advantage that we don't need
915 to sync clocks, and we don't rely on special versions of the krb5
916 library for HMAC_MD4 encryption */
917 return ads_sasl_spnego_ntlmssp_bind(ads
);
924 #define MAX_GSS_PASSES 3
926 /* this performs a SASL/gssapi bind
927 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
928 is very dependent on correctly configured DNS whereas
929 this routine is much less fragile
930 see RFC2078 and RFC2222 for details
932 static ADS_STATUS
ads_sasl_gssapi_do_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
935 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
936 gss_OID mech_type
= GSS_C_NULL_OID
;
937 gss_buffer_desc output_token
, input_token
;
938 uint32 req_flags
, ret_flags
;
941 struct berval
*scred
= NULL
;
945 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
946 uint8 wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
949 input_token
.value
= NULL
;
950 input_token
.length
= 0;
953 * Note: here we always ask the gssapi for sign and seal
954 * as this is negotiated later after the mutal
957 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
| GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
959 for (i
=0; i
< MAX_GSS_PASSES
; i
++) {
960 gss_rc
= gss_init_sec_context(&minor_status
,
977 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
978 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
982 cred
.bv_val
= (char *)output_token
.value
;
983 cred
.bv_len
= output_token
.length
;
985 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
987 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
988 status
= ADS_ERROR(rc
);
992 if (output_token
.value
) {
993 gss_release_buffer(&minor_status
, &output_token
);
997 input_token
.value
= scred
->bv_val
;
998 input_token
.length
= scred
->bv_len
;
1000 input_token
.value
= NULL
;
1001 input_token
.length
= 0;
1004 if (gss_rc
== 0) break;
1007 gss_rc
= gss_unwrap(&minor_status
,context_handle
,&input_token
,&output_token
,
1014 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1018 p
= (uint8
*)output_token
.value
;
1021 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
1025 wrap_type
= CVAL(p
,0);
1027 max_msg_size
= RIVAL(p
,0);
1030 gss_release_buffer(&minor_status
, &output_token
);
1032 if (!(wrap_type
& ads
->ldap
.wrap_type
)) {
1034 * the server doesn't supports the wrap
1037 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1038 ads
->ldap
.wrap_type
, wrap_type
));
1039 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1040 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
1044 /* 0x58 is the minimum windows accepts */
1045 if (max_msg_size
< 0x58) {
1046 max_msg_size
= 0x58;
1049 output_token
.length
= 4;
1050 output_token
.value
= SMB_MALLOC(output_token
.length
);
1051 if (!output_token
.value
) {
1052 output_token
.length
= 0;
1053 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
1056 p
= (uint8
*)output_token
.value
;
1058 RSIVAL(p
,0,max_msg_size
);
1059 SCVAL(p
,0,ads
->ldap
.wrap_type
);
1062 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1063 * but using ads->config.bind_path is the wrong! It should be
1064 * the DN of the user object!
1066 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1067 * is ok and matches the information flow used in GSS-SPNEGO.
1070 gss_rc
= gss_wrap(&minor_status
, context_handle
,0,GSS_C_QOP_DEFAULT
,
1071 &output_token
, /* used as *input* here. */
1073 &input_token
); /* Used as *output* here. */
1075 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1076 output_token
.length
= 0;
1077 SAFE_FREE(output_token
.value
);
1081 /* We've finished with output_token. */
1082 SAFE_FREE(output_token
.value
);
1083 output_token
.length
= 0;
1085 cred
.bv_val
= (char *)input_token
.value
;
1086 cred
.bv_len
= input_token
.length
;
1088 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
1090 gss_release_buffer(&minor_status
, &input_token
);
1091 status
= ADS_ERROR(rc
);
1092 if (!ADS_ERR_OK(status
)) {
1096 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
1097 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
1098 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
1100 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
1102 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1106 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
1107 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
1108 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
1109 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
1110 if (!ADS_ERR_OK(status
)) {
1111 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1112 ads_errstr(status
)));
1115 /* make sure we don't free context_handle */
1116 context_handle
= GSS_C_NO_CONTEXT
;
1121 if (context_handle
!= GSS_C_NO_CONTEXT
)
1122 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
1129 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1132 struct ads_service_principal p
;
1134 status
= ads_generate_service_principal(ads
, NULL
, &p
);
1135 if (!ADS_ERR_OK(status
)) {
1139 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1140 if (ADS_ERR_OK(status
)) {
1141 ads_free_service_principal(&p
);
1145 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1146 "calling kinit\n", ads_errstr(status
)));
1148 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
1150 if (ADS_ERR_OK(status
)) {
1151 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1154 ads_free_service_principal(&p
);
1159 #endif /* HAVE_KRB5 */
1161 /* mapping between SASL mechanisms and functions */
1164 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1165 } sasl_mechanisms
[] = {
1166 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1168 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1173 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1175 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
1181 /* get a list of supported SASL mechanisms */
1182 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
1183 if (!ADS_ERR_OK(status
)) return status
;
1185 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
1187 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
1188 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
1189 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
1190 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1192 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1195 /* try our supported mechanisms in order */
1196 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
1197 /* see if the server supports it */
1198 for (j
=0;values
&& values
[j
];j
++) {
1199 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
1200 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
1202 status
= sasl_mechanisms
[i
].fn(ads
);
1203 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
1204 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
1205 ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
1207 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1208 "retrying with signing enabled\n"));
1209 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1212 ldap_value_free(values
);
1219 ldap_value_free(values
);
1221 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1224 #endif /* HAVE_LDAP */