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"
29 static ADS_STATUS
ads_sasl_ntlmssp_wrap(ADS_STRUCT
*ads
, uint8
*buf
, uint32 len
)
31 struct gensec_security
*gensec_security
=
32 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
33 struct gensec_security
);
35 DATA_BLOB unwrapped
, wrapped
;
36 TALLOC_CTX
*frame
= talloc_stackframe();
38 unwrapped
= data_blob_const(buf
, len
);
40 nt_status
= gensec_wrap(gensec_security
, frame
, &unwrapped
, &wrapped
);
41 if (!NT_STATUS_IS_OK(nt_status
)) {
43 return ADS_ERROR_NT(nt_status
);
46 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
47 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
50 /* copy the wrapped blob to the right location */
51 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.data
, wrapped
.length
);
53 /* set how many bytes must be written to the underlying socket */
54 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
61 static ADS_STATUS
ads_sasl_ntlmssp_unwrap(ADS_STRUCT
*ads
)
63 struct gensec_security
*gensec_security
=
64 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
65 struct gensec_security
);
67 DATA_BLOB unwrapped
, wrapped
;
68 TALLOC_CTX
*frame
= talloc_stackframe();
70 wrapped
= data_blob_const(ads
->ldap
.in
.buf
+ 4, ads
->ldap
.in
.ofs
- 4);
72 nt_status
= gensec_unwrap(gensec_security
, frame
, &wrapped
, &unwrapped
);
73 if (!NT_STATUS_IS_OK(nt_status
)) {
75 return ADS_ERROR_NT(nt_status
);
78 if (wrapped
.length
< unwrapped
.length
) {
80 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
83 /* copy the wrapped blob to the right location */
84 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.data
, unwrapped
.length
);
86 /* set how many bytes must be written to the underlying socket */
87 ads
->ldap
.in
.left
= unwrapped
.length
;
95 static void ads_sasl_ntlmssp_disconnect(ADS_STRUCT
*ads
)
97 struct gensec_security
*gensec_security
=
98 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
99 struct gensec_security
);
101 TALLOC_FREE(gensec_security
);
103 ads
->ldap
.wrap_ops
= NULL
;
104 ads
->ldap
.wrap_private_data
= NULL
;
107 static const struct ads_saslwrap_ops ads_sasl_ntlmssp_ops
= {
109 .wrap
= ads_sasl_ntlmssp_wrap
,
110 .unwrap
= ads_sasl_ntlmssp_unwrap
,
111 .disconnect
= ads_sasl_ntlmssp_disconnect
115 perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
116 we fit on one socket??)
118 static ADS_STATUS
ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT
*ads
)
120 DATA_BLOB msg1
= data_blob_null
;
121 DATA_BLOB blob
= data_blob_null
;
122 DATA_BLOB blob_in
= data_blob_null
;
123 DATA_BLOB blob_out
= data_blob_null
;
124 struct berval cred
, *scred
= NULL
;
130 struct auth_generic_state
*auth_generic_state
;
132 nt_status
= auth_generic_client_prepare(NULL
, &auth_generic_state
);
133 if (!NT_STATUS_IS_OK(nt_status
)) {
134 return ADS_ERROR_NT(nt_status
);
137 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_username(auth_generic_state
, ads
->auth
.user_name
))) {
138 return ADS_ERROR_NT(nt_status
);
140 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_domain(auth_generic_state
, ads
->auth
.realm
))) {
141 return ADS_ERROR_NT(nt_status
);
143 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_password(auth_generic_state
, ads
->auth
.password
))) {
144 return ADS_ERROR_NT(nt_status
);
147 switch (ads
->ldap
.wrap_type
) {
148 case ADS_SASLWRAP_TYPE_SEAL
:
149 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
150 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SEAL
);
152 case ADS_SASLWRAP_TYPE_SIGN
:
153 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
154 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
157 * windows servers are broken with sign only,
158 * so we need to use seal here too
160 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
161 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SEAL
);
162 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
165 case ADS_SASLWRAP_TYPE_PLAIN
:
169 nt_status
= auth_generic_client_start(auth_generic_state
, GENSEC_OID_NTLMSSP
);
170 if (!NT_STATUS_IS_OK(nt_status
)) {
171 return ADS_ERROR_NT(nt_status
);
174 blob_in
= data_blob_null
;
177 nt_status
= gensec_update(auth_generic_state
->gensec_security
,
178 talloc_tos(), NULL
, blob_in
, &blob_out
);
179 data_blob_free(&blob_in
);
180 if ((NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)
181 || NT_STATUS_IS_OK(nt_status
))
182 && blob_out
.length
) {
184 const char *OIDs_ntlm
[] = {OID_NTLMSSP
, NULL
};
185 /* and wrap it in a SPNEGO wrapper */
186 msg1
= spnego_gen_negTokenInit(talloc_tos(),
187 OIDs_ntlm
, &blob_out
, NULL
);
189 /* wrap it in SPNEGO */
190 msg1
= spnego_gen_auth(talloc_tos(), blob_out
);
193 data_blob_free(&blob_out
);
195 cred
.bv_val
= (char *)msg1
.data
;
196 cred
.bv_len
= msg1
.length
;
198 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
, &scred
);
199 data_blob_free(&msg1
);
200 if ((rc
!= LDAP_SASL_BIND_IN_PROGRESS
) && (rc
!= 0)) {
205 TALLOC_FREE(auth_generic_state
);
206 return ADS_ERROR(rc
);
209 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
212 blob
= data_blob_null
;
217 TALLOC_FREE(auth_generic_state
);
218 data_blob_free(&blob_out
);
219 return ADS_ERROR_NT(nt_status
);
223 (rc
== LDAP_SASL_BIND_IN_PROGRESS
)) {
224 DATA_BLOB tmp_blob
= data_blob_null
;
225 /* the server might give us back two challenges */
226 if (!spnego_parse_challenge(talloc_tos(), blob
, &blob_in
,
229 TALLOC_FREE(auth_generic_state
);
230 data_blob_free(&blob
);
231 DEBUG(3,("Failed to parse challenges\n"));
232 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
234 data_blob_free(&tmp_blob
);
235 } else if (rc
== LDAP_SASL_BIND_IN_PROGRESS
) {
236 if (!spnego_parse_auth_response(talloc_tos(), blob
, nt_status
, OID_NTLMSSP
,
239 TALLOC_FREE(auth_generic_state
);
240 data_blob_free(&blob
);
241 DEBUG(3,("Failed to parse auth response\n"));
242 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER
);
245 data_blob_free(&blob
);
246 data_blob_free(&blob_out
);
248 } while (rc
== LDAP_SASL_BIND_IN_PROGRESS
&& !NT_STATUS_IS_OK(nt_status
));
250 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
251 uint32_t sig_size
= gensec_sig_size(auth_generic_state
->gensec_security
, 0);
252 ads
->ldap
.out
.max_unwrapped
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
- sig_size
;
253 ads
->ldap
.out
.sig_size
= sig_size
;
254 ads
->ldap
.in
.min_wrapped
= ads
->ldap
.out
.sig_size
;
255 ads
->ldap
.in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
256 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_ntlmssp_ops
, auth_generic_state
->gensec_security
);
257 if (!ADS_ERR_OK(status
)) {
258 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
259 ads_errstr(status
)));
260 TALLOC_FREE(auth_generic_state
);
263 /* Only keep the gensec_security element around long-term */
264 talloc_steal(NULL
, auth_generic_state
->gensec_security
);
266 TALLOC_FREE(auth_generic_state
);
268 return ADS_ERROR(rc
);
272 static ADS_STATUS
ads_sasl_gssapi_wrap(ADS_STRUCT
*ads
, uint8
*buf
, uint32 len
)
274 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
278 gss_buffer_desc unwrapped
, wrapped
;
279 int conf_req_flag
, conf_state
;
281 unwrapped
.value
= buf
;
282 unwrapped
.length
= len
;
284 /* for now request sign and seal */
285 conf_req_flag
= (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
);
287 gss_rc
= gss_wrap(&minor_status
, context_handle
,
288 conf_req_flag
, GSS_C_QOP_DEFAULT
,
289 &unwrapped
, &conf_state
,
291 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
292 if (!ADS_ERR_OK(status
)) return status
;
294 if (conf_req_flag
&& conf_state
== 0) {
295 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
298 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
299 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
302 /* copy the wrapped blob to the right location */
303 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.value
, wrapped
.length
);
305 /* set how many bytes must be written to the underlying socket */
306 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
308 gss_release_buffer(&minor_status
, &wrapped
);
313 static ADS_STATUS
ads_sasl_gssapi_unwrap(ADS_STRUCT
*ads
)
315 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
319 gss_buffer_desc unwrapped
, wrapped
;
322 wrapped
.value
= ads
->ldap
.in
.buf
+ 4;
323 wrapped
.length
= ads
->ldap
.in
.ofs
- 4;
325 gss_rc
= gss_unwrap(&minor_status
, context_handle
,
326 &wrapped
, &unwrapped
,
327 &conf_state
, GSS_C_QOP_DEFAULT
);
328 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
329 if (!ADS_ERR_OK(status
)) return status
;
331 if (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
&& conf_state
== 0) {
332 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
335 if (wrapped
.length
< unwrapped
.length
) {
336 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
339 /* copy the wrapped blob to the right location */
340 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.value
, unwrapped
.length
);
342 /* set how many bytes must be written to the underlying socket */
343 ads
->ldap
.in
.left
= unwrapped
.length
;
344 ads
->ldap
.in
.ofs
= 4;
346 gss_release_buffer(&minor_status
, &unwrapped
);
351 static void ads_sasl_gssapi_disconnect(ADS_STRUCT
*ads
)
353 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
356 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
358 ads
->ldap
.wrap_ops
= NULL
;
359 ads
->ldap
.wrap_private_data
= NULL
;
362 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops
= {
364 .wrap
= ads_sasl_gssapi_wrap
,
365 .unwrap
= ads_sasl_gssapi_unwrap
,
366 .disconnect
= ads_sasl_gssapi_disconnect
370 perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
372 static ADS_STATUS
ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
378 gss_OID_desc krb5_mech_type
=
379 {9, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
380 gss_OID mech_type
= &krb5_mech_type
;
381 gss_OID actual_mech_type
= GSS_C_NULL_OID
;
382 const char *spnego_mechs
[] = {OID_KERBEROS5_OLD
, OID_KERBEROS5
, OID_NTLMSSP
, NULL
};
383 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
384 gss_buffer_desc input_token
, output_token
;
385 uint32 req_flags
, ret_flags
;
386 uint32 req_tmp
, ret_tmp
;
389 struct berval cred
, *scred
= NULL
;
391 input_token
.value
= NULL
;
392 input_token
.length
= 0;
394 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
;
395 switch (ads
->ldap
.wrap_type
) {
396 case ADS_SASLWRAP_TYPE_SEAL
:
397 req_flags
|= GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
399 case ADS_SASLWRAP_TYPE_SIGN
:
400 req_flags
|= GSS_C_INTEG_FLAG
;
402 case ADS_SASLWRAP_TYPE_PLAIN
:
406 /* Note: here we explicit ask for the krb5 mech_type */
407 gss_rc
= gss_init_sec_context(&minor_status
,
420 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
421 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
426 * As some gssapi krb5 mech implementations
427 * automaticly add GSS_C_INTEG_FLAG and GSS_C_CONF_FLAG
428 * to req_flags internaly, it's not possible to
429 * use plain or signing only connection via
430 * the gssapi interface.
432 * Because of this we need to check it the ret_flags
433 * has more flags as req_flags and correct the value
434 * of ads->ldap.wrap_type.
436 * I ads->auth.flags has ADS_AUTH_SASL_FORCE
437 * we need to give an error.
439 req_tmp
= req_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
440 ret_tmp
= ret_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
442 if (req_tmp
== ret_tmp
) {
443 /* everythings fine... */
445 } else if (req_flags
& GSS_C_CONF_FLAG
) {
447 * here we wanted sealing but didn't got it
448 * from the gssapi library
450 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
453 } else if ((req_flags
& GSS_C_INTEG_FLAG
) &&
454 !(ret_flags
& GSS_C_INTEG_FLAG
)) {
456 * here we wanted siging but didn't got it
457 * from the gssapi library
459 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
462 } else if (ret_flags
& GSS_C_CONF_FLAG
) {
464 * here we didn't want sealing
465 * but the gssapi library forces it
466 * so correct the needed wrap_type if
467 * the caller didn't forced siging only
469 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
470 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
474 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
475 req_flags
= ret_flags
;
477 } else if (ret_flags
& GSS_C_INTEG_FLAG
) {
479 * here we didn't want signing
480 * but the gssapi library forces it
481 * so correct the needed wrap_type if
482 * the caller didn't forced plain
484 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
485 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
489 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
490 req_flags
= ret_flags
;
493 * This could (should?) not happen
495 status
= ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
500 /* and wrap that in a shiny SPNEGO wrapper */
501 unwrapped
= data_blob_const(output_token
.value
, output_token
.length
);
502 wrapped
= spnego_gen_negTokenInit(talloc_tos(),
503 spnego_mechs
, &unwrapped
, NULL
);
504 gss_release_buffer(&minor_status
, &output_token
);
505 if (unwrapped
.length
> wrapped
.length
) {
506 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
510 cred
.bv_val
= (char *)wrapped
.data
;
511 cred
.bv_len
= wrapped
.length
;
513 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
,
515 data_blob_free(&wrapped
);
516 if (rc
!= LDAP_SUCCESS
) {
517 status
= ADS_ERROR(rc
);
522 wrapped
= data_blob_const(scred
->bv_val
, scred
->bv_len
);
524 wrapped
= data_blob_null
;
527 ok
= spnego_parse_auth_response(talloc_tos(), wrapped
, NT_STATUS_OK
,
530 if (scred
) ber_bvfree(scred
);
532 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
536 input_token
.value
= unwrapped
.data
;
537 input_token
.length
= unwrapped
.length
;
540 * As we asked for mutal authentication
541 * we need to pass the servers response
544 gss_rc
= gss_init_sec_context(&minor_status
,
557 data_blob_free(&unwrapped
);
559 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
563 gss_release_buffer(&minor_status
, &output_token
);
566 * If we the sign and seal options
567 * doesn't match after getting the response
568 * from the server, we don't want to use the connection
570 req_tmp
= req_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
571 ret_tmp
= ret_flags
& (GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
);
573 if (req_tmp
!= ret_tmp
) {
574 /* everythings fine... */
575 status
= ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
579 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
580 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
582 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
583 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
585 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
587 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
591 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
592 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
593 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
594 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
595 if (!ADS_ERR_OK(status
)) {
596 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
597 ads_errstr(status
)));
600 /* make sure we don't free context_handle */
601 context_handle
= GSS_C_NO_CONTEXT
;
604 status
= ADS_SUCCESS
;
607 if (context_handle
!= GSS_C_NO_CONTEXT
)
608 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
612 #endif /* HAVE_KRB5 */
615 struct ads_service_principal
{
622 static void ads_free_service_principal(struct ads_service_principal
*p
)
624 SAFE_FREE(p
->string
);
629 gss_release_name(&minor_status
, &p
->name
);
636 static ADS_STATUS
ads_guess_service_principal(ADS_STRUCT
*ads
,
637 char **returned_principal
)
641 if (ads
->server
.realm
&& ads
->server
.ldap_server
) {
642 char *server
, *server_realm
;
644 server
= SMB_STRDUP(ads
->server
.ldap_server
);
645 server_realm
= SMB_STRDUP(ads
->server
.realm
);
647 if (!server
|| !server_realm
) {
649 SAFE_FREE(server_realm
);
650 return ADS_ERROR(LDAP_NO_MEMORY
);
654 strupper_m(server_realm
);
655 if (asprintf(&princ
, "ldap/%s@%s", server
, server_realm
) == -1) {
657 SAFE_FREE(server_realm
);
658 return ADS_ERROR(LDAP_NO_MEMORY
);
662 SAFE_FREE(server_realm
);
665 return ADS_ERROR(LDAP_NO_MEMORY
);
667 } else if (ads
->config
.realm
&& ads
->config
.ldap_server_name
) {
668 char *server
, *server_realm
;
670 server
= SMB_STRDUP(ads
->config
.ldap_server_name
);
671 server_realm
= SMB_STRDUP(ads
->config
.realm
);
673 if (!server
|| !server_realm
) {
675 SAFE_FREE(server_realm
);
676 return ADS_ERROR(LDAP_NO_MEMORY
);
680 strupper_m(server_realm
);
681 if (asprintf(&princ
, "ldap/%s@%s", server
, server_realm
) == -1) {
683 SAFE_FREE(server_realm
);
684 return ADS_ERROR(LDAP_NO_MEMORY
);
688 SAFE_FREE(server_realm
);
691 return ADS_ERROR(LDAP_NO_MEMORY
);
696 return ADS_ERROR(LDAP_PARAM_ERROR
);
699 *returned_principal
= princ
;
704 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
705 const char *given_principal
,
706 struct ads_service_principal
*p
)
710 gss_buffer_desc input_name
;
711 /* GSS_KRB5_NT_PRINCIPAL_NAME */
712 gss_OID_desc nt_principal
=
713 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
720 /* I've seen a child Windows 2000 domain not send
721 the principal name back in the first round of
722 the SASL bind reply. So we guess based on server
723 name and realm. --jerry */
724 /* Also try best guess when we get the w2k8 ignore principal
725 back, or when we are configured to ignore it - gd,
728 if (!lp_client_use_spnego_principal() ||
730 strequal(given_principal
, ADS_IGNORE_PRINCIPAL
)) {
732 status
= ads_guess_service_principal(ads
, &p
->string
);
733 if (!ADS_ERR_OK(status
)) {
737 p
->string
= SMB_STRDUP(given_principal
);
739 return ADS_ERROR(LDAP_NO_MEMORY
);
744 input_name
.value
= p
->string
;
745 input_name
.length
= strlen(p
->string
);
747 gss_rc
= gss_import_name(&minor_status
, &input_name
, &nt_principal
, &p
->name
);
749 ads_free_service_principal(p
);
750 return ADS_ERROR_GSS(gss_rc
, minor_status
);
758 perform a LDAP/SASL/SPNEGO/KRB5 bind
760 static ADS_STATUS
ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT
*ads
, const char *principal
)
762 DATA_BLOB blob
= data_blob_null
;
763 struct berval cred
, *scred
= NULL
;
764 DATA_BLOB session_key
= data_blob_null
;
767 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
768 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
771 rc
= spnego_gen_krb5_negTokenInit(talloc_tos(), principal
,
772 ads
->auth
.time_offset
, &blob
, &session_key
, 0,
773 &ads
->auth
.tgs_expire
);
776 return ADS_ERROR_KRB5(rc
);
779 /* now send the auth packet and we should be done */
780 cred
.bv_val
= (char *)blob
.data
;
781 cred
.bv_len
= blob
.length
;
783 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", &cred
, NULL
, NULL
, &scred
);
785 data_blob_free(&blob
);
786 data_blob_free(&session_key
);
790 return ADS_ERROR(rc
);
793 static ADS_STATUS
ads_sasl_spnego_krb5_bind(ADS_STRUCT
*ads
,
794 struct ads_service_principal
*p
)
798 * we only use the gsskrb5 based implementation
799 * when sasl sign or seal is requested.
801 * This has the following reasons:
802 * - it's likely that the gssapi krb5 mech implementation
803 * doesn't support to negotiate plain connections
804 * - the ads_sasl_spnego_rawkrb5_bind is more robust
805 * against clock skew errors
807 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
808 return ads_sasl_spnego_gsskrb5_bind(ads
, p
->name
);
811 return ads_sasl_spnego_rawkrb5_bind(ads
, p
->string
);
813 #endif /* HAVE_KRB5 */
816 this performs a SASL/SPNEGO bind
818 static ADS_STATUS
ads_sasl_spnego_bind(ADS_STRUCT
*ads
)
820 struct berval
*scred
=NULL
;
824 char *given_principal
= NULL
;
825 char *OIDs
[ASN1_MAX_OIDS
];
827 bool got_kerberos_mechanism
= False
;
830 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", NULL
, NULL
, NULL
, &scred
);
832 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
833 status
= ADS_ERROR(rc
);
837 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
842 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
845 /* the server sent us the first part of the SPNEGO exchange in the negprot
847 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
849 data_blob_free(&blob
);
850 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
853 data_blob_free(&blob
);
855 /* make sure the server understands kerberos */
856 for (i
=0;OIDs
[i
];i
++) {
857 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs
[i
]));
859 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
860 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
861 got_kerberos_mechanism
= True
;
864 talloc_free(OIDs
[i
]);
866 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal
));
869 if (!(ads
->auth
.flags
& ADS_AUTH_DISABLE_KERBEROS
) &&
870 got_kerberos_mechanism
)
872 struct ads_service_principal p
;
874 status
= ads_generate_service_principal(ads
, given_principal
, &p
);
875 TALLOC_FREE(given_principal
);
876 if (!ADS_ERR_OK(status
)) {
880 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
881 if (ADS_ERR_OK(status
)) {
882 ads_free_service_principal(&p
);
886 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
887 "calling kinit\n", ads_errstr(status
)));
889 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
891 if (ADS_ERR_OK(status
)) {
892 status
= ads_sasl_spnego_krb5_bind(ads
, &p
);
893 if (!ADS_ERR_OK(status
)) {
894 DEBUG(0,("kinit succeeded but "
895 "ads_sasl_spnego_krb5_bind failed: %s\n",
896 ads_errstr(status
)));
900 ads_free_service_principal(&p
);
902 /* only fallback to NTLMSSP if allowed */
903 if (ADS_ERR_OK(status
) ||
904 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
910 TALLOC_FREE(given_principal
);
913 /* lets do NTLMSSP ... this has the big advantage that we don't need
914 to sync clocks, and we don't rely on special versions of the krb5
915 library for HMAC_MD4 encryption */
916 return ads_sasl_spnego_ntlmssp_bind(ads
);
923 #define MAX_GSS_PASSES 3
925 /* this performs a SASL/gssapi bind
926 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
927 is very dependent on correctly configured DNS whereas
928 this routine is much less fragile
929 see RFC2078 and RFC2222 for details
931 static ADS_STATUS
ads_sasl_gssapi_do_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
934 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
935 gss_OID mech_type
= GSS_C_NULL_OID
;
936 gss_buffer_desc output_token
, input_token
;
937 uint32 req_flags
, ret_flags
;
940 struct berval
*scred
= NULL
;
944 uint32 max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
945 uint8 wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
948 input_token
.value
= NULL
;
949 input_token
.length
= 0;
952 * Note: here we always ask the gssapi for sign and seal
953 * as this is negotiated later after the mutal
956 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
| GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
958 for (i
=0; i
< MAX_GSS_PASSES
; i
++) {
959 gss_rc
= gss_init_sec_context(&minor_status
,
976 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
977 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
981 cred
.bv_val
= (char *)output_token
.value
;
982 cred
.bv_len
= output_token
.length
;
984 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
986 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
987 status
= ADS_ERROR(rc
);
991 if (output_token
.value
) {
992 gss_release_buffer(&minor_status
, &output_token
);
996 input_token
.value
= scred
->bv_val
;
997 input_token
.length
= scred
->bv_len
;
999 input_token
.value
= NULL
;
1000 input_token
.length
= 0;
1003 if (gss_rc
== 0) break;
1006 gss_rc
= gss_unwrap(&minor_status
,context_handle
,&input_token
,&output_token
,
1013 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1017 p
= (uint8
*)output_token
.value
;
1020 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
1024 wrap_type
= CVAL(p
,0);
1026 max_msg_size
= RIVAL(p
,0);
1029 gss_release_buffer(&minor_status
, &output_token
);
1031 if (!(wrap_type
& ads
->ldap
.wrap_type
)) {
1033 * the server doesn't supports the wrap
1036 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
1037 ads
->ldap
.wrap_type
, wrap_type
));
1038 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
1039 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
1043 /* 0x58 is the minimum windows accepts */
1044 if (max_msg_size
< 0x58) {
1045 max_msg_size
= 0x58;
1048 output_token
.length
= 4;
1049 output_token
.value
= SMB_MALLOC(output_token
.length
);
1050 if (!output_token
.value
) {
1051 output_token
.length
= 0;
1052 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
1055 p
= (uint8
*)output_token
.value
;
1057 RSIVAL(p
,0,max_msg_size
);
1058 SCVAL(p
,0,ads
->ldap
.wrap_type
);
1061 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
1062 * but using ads->config.bind_path is the wrong! It should be
1063 * the DN of the user object!
1065 * w2k3 gives an error when we send an incorrect DN, but sending nothing
1066 * is ok and matches the information flow used in GSS-SPNEGO.
1069 gss_rc
= gss_wrap(&minor_status
, context_handle
,0,GSS_C_QOP_DEFAULT
,
1070 &output_token
, /* used as *input* here. */
1072 &input_token
); /* Used as *output* here. */
1074 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1075 output_token
.length
= 0;
1076 SAFE_FREE(output_token
.value
);
1080 /* We've finished with output_token. */
1081 SAFE_FREE(output_token
.value
);
1082 output_token
.length
= 0;
1084 cred
.bv_val
= (char *)input_token
.value
;
1085 cred
.bv_len
= input_token
.length
;
1087 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
1089 gss_release_buffer(&minor_status
, &input_token
);
1090 status
= ADS_ERROR(rc
);
1091 if (!ADS_ERR_OK(status
)) {
1095 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
1096 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
1097 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
1099 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
1101 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1105 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
1106 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
1107 ads
->ldap
.in
.max_wrapped
= max_msg_size
;
1108 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
1109 if (!ADS_ERR_OK(status
)) {
1110 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1111 ads_errstr(status
)));
1114 /* make sure we don't free context_handle */
1115 context_handle
= GSS_C_NO_CONTEXT
;
1120 if (context_handle
!= GSS_C_NO_CONTEXT
)
1121 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
1128 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1131 struct ads_service_principal p
;
1133 status
= ads_generate_service_principal(ads
, NULL
, &p
);
1134 if (!ADS_ERR_OK(status
)) {
1138 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1139 if (ADS_ERR_OK(status
)) {
1140 ads_free_service_principal(&p
);
1144 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1145 "calling kinit\n", ads_errstr(status
)));
1147 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
1149 if (ADS_ERR_OK(status
)) {
1150 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1153 ads_free_service_principal(&p
);
1158 #endif /* HAVE_KRB5 */
1160 /* mapping between SASL mechanisms and functions */
1163 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1164 } sasl_mechanisms
[] = {
1165 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1167 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1172 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1174 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
1180 /* get a list of supported SASL mechanisms */
1181 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
1182 if (!ADS_ERR_OK(status
)) return status
;
1184 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
1186 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
1187 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
1188 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
1189 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1191 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1194 /* try our supported mechanisms in order */
1195 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
1196 /* see if the server supports it */
1197 for (j
=0;values
&& values
[j
];j
++) {
1198 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
1199 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
1201 status
= sasl_mechanisms
[i
].fn(ads
);
1202 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
1203 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
1204 ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
1206 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1207 "retrying with signing enabled\n"));
1208 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1211 ldap_value_free(values
);
1218 ldap_value_free(values
);
1220 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1223 #endif /* HAVE_LDAP */