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/credentials/credentials.h"
23 #include "auth/gensec/gensec.h"
24 #include "auth_generic.h"
27 #include "system/gssapi.h"
28 #include "lib/param/loadparm.h"
33 static ADS_STATUS
ads_sasl_gensec_wrap(ADS_STRUCT
*ads
, uint8_t *buf
, uint32_t len
)
35 struct gensec_security
*gensec_security
=
36 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
37 struct gensec_security
);
39 DATA_BLOB unwrapped
, wrapped
;
40 TALLOC_CTX
*frame
= talloc_stackframe();
42 unwrapped
= data_blob_const(buf
, len
);
44 nt_status
= gensec_wrap(gensec_security
, frame
, &unwrapped
, &wrapped
);
45 if (!NT_STATUS_IS_OK(nt_status
)) {
47 return ADS_ERROR_NT(nt_status
);
50 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
52 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
55 /* copy the wrapped blob to the right location */
56 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.data
, wrapped
.length
);
58 /* set how many bytes must be written to the underlying socket */
59 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
66 static ADS_STATUS
ads_sasl_gensec_unwrap(ADS_STRUCT
*ads
)
68 struct gensec_security
*gensec_security
=
69 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
70 struct gensec_security
);
72 DATA_BLOB unwrapped
, wrapped
;
73 TALLOC_CTX
*frame
= talloc_stackframe();
75 wrapped
= data_blob_const(ads
->ldap
.in
.buf
+ 4, ads
->ldap
.in
.ofs
- 4);
77 nt_status
= gensec_unwrap(gensec_security
, frame
, &wrapped
, &unwrapped
);
78 if (!NT_STATUS_IS_OK(nt_status
)) {
80 return ADS_ERROR_NT(nt_status
);
83 if (wrapped
.length
< unwrapped
.length
) {
85 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
88 /* copy the wrapped blob to the right location */
89 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.data
, unwrapped
.length
);
91 /* set how many bytes must be written to the underlying socket */
92 ads
->ldap
.in
.left
= unwrapped
.length
;
100 static void ads_sasl_gensec_disconnect(ADS_STRUCT
*ads
)
102 struct gensec_security
*gensec_security
=
103 talloc_get_type_abort(ads
->ldap
.wrap_private_data
,
104 struct gensec_security
);
106 TALLOC_FREE(gensec_security
);
108 ads
->ldap
.wrap_ops
= NULL
;
109 ads
->ldap
.wrap_private_data
= NULL
;
112 static const struct ads_saslwrap_ops ads_sasl_gensec_ops
= {
114 .wrap
= ads_sasl_gensec_wrap
,
115 .unwrap
= ads_sasl_gensec_unwrap
,
116 .disconnect
= ads_sasl_gensec_disconnect
120 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
121 we fit on one socket??)
123 static ADS_STATUS
ads_sasl_spnego_gensec_bind(ADS_STRUCT
*ads
,
125 enum credentials_use_kerberos krb5_state
,
126 const char *target_service
,
127 const char *target_hostname
,
128 const DATA_BLOB server_blob
)
130 DATA_BLOB blob_in
= data_blob_null
;
131 DATA_BLOB blob_out
= data_blob_null
;
135 struct auth_generic_state
*auth_generic_state
;
136 bool use_spnego_principal
= lp_client_use_spnego_principal();
137 const char *sasl_list
[] = { sasl
, NULL
};
140 nt_status
= auth_generic_client_prepare(NULL
, &auth_generic_state
);
141 if (!NT_STATUS_IS_OK(nt_status
)) {
142 return ADS_ERROR_NT(nt_status
);
145 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_username(auth_generic_state
, ads
->auth
.user_name
))) {
146 return ADS_ERROR_NT(nt_status
);
148 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_domain(auth_generic_state
, ads
->auth
.realm
))) {
149 return ADS_ERROR_NT(nt_status
);
151 if (!NT_STATUS_IS_OK(nt_status
= auth_generic_set_password(auth_generic_state
, ads
->auth
.password
))) {
152 return ADS_ERROR_NT(nt_status
);
155 if (server_blob
.length
== 0) {
156 use_spnego_principal
= false;
159 if (krb5_state
== CRED_DONT_USE_KERBEROS
) {
160 use_spnego_principal
= false;
163 cli_credentials_set_kerberos_state(auth_generic_state
->credentials
,
166 if (target_service
!= NULL
) {
167 nt_status
= gensec_set_target_service(
168 auth_generic_state
->gensec_security
,
170 if (!NT_STATUS_IS_OK(nt_status
)) {
171 return ADS_ERROR_NT(nt_status
);
175 if (target_hostname
!= NULL
) {
176 nt_status
= gensec_set_target_hostname(
177 auth_generic_state
->gensec_security
,
179 if (!NT_STATUS_IS_OK(nt_status
)) {
180 return ADS_ERROR_NT(nt_status
);
184 if (target_service
!= NULL
&& target_hostname
!= NULL
) {
185 use_spnego_principal
= false;
188 switch (ads
->ldap
.wrap_type
) {
189 case ADS_SASLWRAP_TYPE_SEAL
:
190 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
191 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SEAL
);
193 case ADS_SASLWRAP_TYPE_SIGN
:
194 if (ads
->auth
.flags
& ADS_AUTH_SASL_FORCE
) {
195 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
198 * windows servers are broken with sign only,
199 * so we let the NTLMSSP backend to seal here,
200 * via GENSEC_FEATURE_LDAP_STYLE.
202 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_SIGN
);
203 gensec_want_feature(auth_generic_state
->gensec_security
, GENSEC_FEATURE_LDAP_STYLE
);
206 case ADS_SASLWRAP_TYPE_PLAIN
:
210 nt_status
= auth_generic_client_start_by_sasl(auth_generic_state
,
212 if (!NT_STATUS_IS_OK(nt_status
)) {
213 return ADS_ERROR_NT(nt_status
);
216 rc
= LDAP_SASL_BIND_IN_PROGRESS
;
217 nt_status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
218 if (use_spnego_principal
) {
219 blob_in
= data_blob_dup_talloc(talloc_tos(), server_blob
);
220 if (blob_in
.length
== 0) {
221 TALLOC_FREE(auth_generic_state
);
222 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
225 blob_in
= data_blob_null
;
227 blob_out
= data_blob_null
;
230 struct berval cred
, *scred
= NULL
;
232 nt_status
= gensec_update(auth_generic_state
->gensec_security
,
233 talloc_tos(), blob_in
, &blob_out
);
234 data_blob_free(&blob_in
);
235 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)
236 && !NT_STATUS_IS_OK(nt_status
))
238 TALLOC_FREE(auth_generic_state
);
239 data_blob_free(&blob_out
);
240 return ADS_ERROR_NT(nt_status
);
243 if (NT_STATUS_IS_OK(nt_status
) && rc
== 0 && blob_out
.length
== 0) {
247 cred
.bv_val
= (char *)blob_out
.data
;
248 cred
.bv_len
= blob_out
.length
;
250 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, sasl
, &cred
, NULL
, NULL
, &scred
);
251 data_blob_free(&blob_out
);
252 if ((rc
!= LDAP_SASL_BIND_IN_PROGRESS
) && (rc
!= 0)) {
257 TALLOC_FREE(auth_generic_state
);
258 return ADS_ERROR(rc
);
261 blob_in
= data_blob_talloc(talloc_tos(),
264 if (blob_in
.length
!= scred
->bv_len
) {
266 TALLOC_FREE(auth_generic_state
);
267 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
271 blob_in
= data_blob_null
;
273 if (NT_STATUS_IS_OK(nt_status
) && rc
== 0 && blob_in
.length
== 0) {
278 data_blob_free(&blob_in
);
279 data_blob_free(&blob_out
);
281 if (ads
->ldap
.wrap_type
>= ADS_SASLWRAP_TYPE_SEAL
) {
284 ok
= gensec_have_feature(auth_generic_state
->gensec_security
,
285 GENSEC_FEATURE_SEAL
);
287 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
288 TALLOC_FREE(auth_generic_state
);
289 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
292 ok
= gensec_have_feature(auth_generic_state
->gensec_security
,
293 GENSEC_FEATURE_SIGN
);
295 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
296 TALLOC_FREE(auth_generic_state
);
297 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
300 } else if (ads
->ldap
.wrap_type
>= ADS_SASLWRAP_TYPE_SIGN
) {
303 ok
= gensec_have_feature(auth_generic_state
->gensec_security
,
304 GENSEC_FEATURE_SIGN
);
306 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
307 TALLOC_FREE(auth_generic_state
);
308 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE
);
312 ads
->auth
.tgs_expire
= LONG_MAX
;
313 end_nt_time
= gensec_expire_time(auth_generic_state
->gensec_security
);
314 if (end_nt_time
!= GENSEC_EXPIRE_TIME_INFINITY
) {
316 nttime_to_timeval(&tv
, end_nt_time
);
317 ads
->auth
.tgs_expire
= tv
.tv_sec
;
320 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
321 size_t max_wrapped
= gensec_max_wrapped_size(auth_generic_state
->gensec_security
);
322 ads
->ldap
.out
.max_unwrapped
= gensec_max_input_size(auth_generic_state
->gensec_security
);
324 ads
->ldap
.out
.sig_size
= max_wrapped
- ads
->ldap
.out
.max_unwrapped
;
326 * Note that we have to truncate this to 0x2C
327 * (taken from a capture with LDAP unbind), as the
328 * signature size is not constant for Kerberos with
331 ads
->ldap
.in
.min_wrapped
= MIN(ads
->ldap
.out
.sig_size
, 0x2C);
332 ads
->ldap
.in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
333 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gensec_ops
, auth_generic_state
->gensec_security
);
334 if (!ADS_ERR_OK(status
)) {
335 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
336 ads_errstr(status
)));
337 TALLOC_FREE(auth_generic_state
);
340 /* Only keep the gensec_security element around long-term */
341 talloc_steal(NULL
, auth_generic_state
->gensec_security
);
343 TALLOC_FREE(auth_generic_state
);
345 return ADS_ERROR(rc
);
349 static ADS_STATUS
ads_init_gssapi_cred(ADS_STRUCT
*ads
, gss_cred_id_t
*cred
)
353 krb5_error_code kerr
;
354 krb5_ccache kccache
= NULL
;
357 *cred
= GSS_C_NO_CREDENTIAL
;
359 if (!ads
->auth
.ccache_name
) {
363 kerr
= krb5_init_context(&kctx
);
365 return ADS_ERROR_KRB5(kerr
);
368 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
369 kerr
= krb5_cc_resolve(kctx
, ads
->auth
.ccache_name
, &kccache
);
371 status
= ADS_ERROR_KRB5(kerr
);
375 maj
= gss_krb5_import_cred(&min
, kccache
, NULL
, NULL
, cred
);
376 if (maj
!= GSS_S_COMPLETE
) {
377 status
= ADS_ERROR_GSS(maj
, min
);
381 /* We need to fallback to overriding the default creds.
382 * This operation is not thread safe as it changes the process
383 * environment variable, but we do not have any better option
384 * with older kerberos libraries */
386 const char *oldccname
= NULL
;
388 oldccname
= getenv("KRB5CCNAME");
389 setenv("KRB5CCNAME", ads
->auth
.ccache_name
, 1);
391 maj
= gss_acquire_cred(&min
, GSS_C_NO_NAME
, GSS_C_INDEFINITE
,
392 NULL
, GSS_C_INITIATE
, cred
, NULL
, NULL
);
395 setenv("KRB5CCNAME", oldccname
, 1);
397 unsetenv("KRB5CCNAME");
400 if (maj
!= GSS_S_COMPLETE
) {
401 status
= ADS_ERROR_GSS(maj
, min
);
407 status
= ADS_SUCCESS
;
410 if (!ADS_ERR_OK(status
) && kccache
!= NULL
) {
411 krb5_cc_close(kctx
, kccache
);
413 krb5_free_context(kctx
);
417 static ADS_STATUS
ads_sasl_gssapi_wrap(ADS_STRUCT
*ads
, uint8_t *buf
, uint32_t len
)
419 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
422 uint32_t minor_status
;
423 gss_buffer_desc unwrapped
, wrapped
;
424 int conf_req_flag
, conf_state
;
426 unwrapped
.value
= buf
;
427 unwrapped
.length
= len
;
429 /* for now request sign and seal */
430 conf_req_flag
= (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
);
432 gss_rc
= gss_wrap(&minor_status
, context_handle
,
433 conf_req_flag
, GSS_C_QOP_DEFAULT
,
434 &unwrapped
, &conf_state
,
436 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
437 if (!ADS_ERR_OK(status
)) return status
;
439 if (conf_req_flag
&& conf_state
== 0) {
440 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
443 if ((ads
->ldap
.out
.size
- 4) < wrapped
.length
) {
444 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
447 /* copy the wrapped blob to the right location */
448 memcpy(ads
->ldap
.out
.buf
+ 4, wrapped
.value
, wrapped
.length
);
450 /* set how many bytes must be written to the underlying socket */
451 ads
->ldap
.out
.left
= 4 + wrapped
.length
;
453 gss_release_buffer(&minor_status
, &wrapped
);
458 static ADS_STATUS
ads_sasl_gssapi_unwrap(ADS_STRUCT
*ads
)
460 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
463 uint32_t minor_status
;
464 gss_buffer_desc unwrapped
, wrapped
;
467 wrapped
.value
= ads
->ldap
.in
.buf
+ 4;
468 wrapped
.length
= ads
->ldap
.in
.ofs
- 4;
470 gss_rc
= gss_unwrap(&minor_status
, context_handle
,
471 &wrapped
, &unwrapped
,
472 &conf_state
, GSS_C_QOP_DEFAULT
);
473 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
474 if (!ADS_ERR_OK(status
)) return status
;
476 if (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
&& conf_state
== 0) {
477 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED
);
480 if (wrapped
.length
< unwrapped
.length
) {
481 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
484 /* copy the wrapped blob to the right location */
485 memcpy(ads
->ldap
.in
.buf
+ 4, unwrapped
.value
, unwrapped
.length
);
487 /* set how many bytes must be written to the underlying socket */
488 ads
->ldap
.in
.left
= unwrapped
.length
;
489 ads
->ldap
.in
.ofs
= 4;
491 gss_release_buffer(&minor_status
, &unwrapped
);
496 static void ads_sasl_gssapi_disconnect(ADS_STRUCT
*ads
)
498 gss_ctx_id_t context_handle
= (gss_ctx_id_t
)ads
->ldap
.wrap_private_data
;
499 uint32_t minor_status
;
501 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
503 ads
->ldap
.wrap_ops
= NULL
;
504 ads
->ldap
.wrap_private_data
= NULL
;
507 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops
= {
509 .wrap
= ads_sasl_gssapi_wrap
,
510 .unwrap
= ads_sasl_gssapi_unwrap
,
511 .disconnect
= ads_sasl_gssapi_disconnect
514 #endif /* HAVE_KRB5 */
517 struct ads_service_principal
{
526 static void ads_free_service_principal(struct ads_service_principal
*p
)
528 SAFE_FREE(p
->service
);
529 SAFE_FREE(p
->hostname
);
530 SAFE_FREE(p
->string
);
534 uint32_t minor_status
;
535 gss_release_name(&minor_status
, &p
->name
);
541 static ADS_STATUS
ads_guess_target(ADS_STRUCT
*ads
,
546 ADS_STATUS status
= ADS_ERROR(LDAP_NO_MEMORY
);
553 frame
= talloc_stackframe();
555 return ADS_ERROR(LDAP_NO_MEMORY
);
558 if (ads
->server
.realm
&& ads
->server
.ldap_server
) {
559 server
= strlower_talloc(frame
, ads
->server
.ldap_server
);
560 if (server
== NULL
) {
564 realm
= strupper_talloc(frame
, ads
->server
.realm
);
570 * If we got a name which is bigger than a NetBIOS name,
571 * but isn't a FQDN, create one.
573 if (strlen(server
) > 15 && strstr(server
, ".") == NULL
) {
576 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
577 if (dnsdomain
== NULL
) {
581 server
= talloc_asprintf(frame
,
584 if (server
== NULL
) {
588 } else if (ads
->config
.realm
&& ads
->config
.ldap_server_name
) {
589 server
= strlower_talloc(frame
, ads
->config
.ldap_server_name
);
590 if (server
== NULL
) {
594 realm
= strupper_talloc(frame
, ads
->config
.realm
);
600 * If we got a name which is bigger than a NetBIOS name,
601 * but isn't a FQDN, create one.
603 if (strlen(server
) > 15 && strstr(server
, ".") == NULL
) {
606 dnsdomain
= strlower_talloc(frame
, ads
->server
.realm
);
607 if (dnsdomain
== NULL
) {
611 server
= talloc_asprintf(frame
,
614 if (server
== NULL
) {
620 if (server
== NULL
|| realm
== NULL
) {
624 *service
= SMB_STRDUP("ldap");
625 if (*service
== NULL
) {
626 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
629 *hostname
= SMB_STRDUP(server
);
630 if (*hostname
== NULL
) {
632 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
635 rc
= asprintf(&princ
, "ldap/%s@%s", server
, realm
);
636 if (rc
== -1 || princ
== NULL
) {
638 SAFE_FREE(*hostname
);
639 status
= ADS_ERROR(LDAP_PARAM_ERROR
);
645 status
= ADS_SUCCESS
;
651 static ADS_STATUS
ads_generate_service_principal(ADS_STRUCT
*ads
,
652 struct ads_service_principal
*p
)
656 gss_buffer_desc input_name
;
657 /* GSS_KRB5_NT_PRINCIPAL_NAME */
658 gss_OID_desc nt_principal
=
659 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
660 uint32_t minor_status
;
666 status
= ads_guess_target(ads
,
670 if (!ADS_ERR_OK(status
)) {
675 input_name
.value
= p
->string
;
676 input_name
.length
= strlen(p
->string
);
678 gss_rc
= gss_import_name(&minor_status
, &input_name
, &nt_principal
, &p
->name
);
680 ads_free_service_principal(p
);
681 return ADS_ERROR_GSS(gss_rc
, minor_status
);
688 #endif /* HAVE_KRB5 */
691 this performs a SASL/SPNEGO bind
693 static ADS_STATUS
ads_sasl_spnego_bind(ADS_STRUCT
*ads
)
695 TALLOC_CTX
*frame
= talloc_stackframe();
696 struct ads_service_principal p
= {0};
697 struct berval
*scred
=NULL
;
700 DATA_BLOB blob
= data_blob_null
;
701 char *given_principal
= NULL
;
702 char *OIDs
[ASN1_MAX_OIDS
];
704 bool got_kerberos_mechanism
= False
;
707 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSS-SPNEGO", NULL
, NULL
, NULL
, &scred
);
709 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
710 status
= ADS_ERROR(rc
);
714 blob
= data_blob(scred
->bv_val
, scred
->bv_len
);
719 file_save("sasl_spnego.dat", blob
.data
, blob
.length
);
722 /* the server sent us the first part of the SPNEGO exchange in the negprot
724 if (!spnego_parse_negTokenInit(talloc_tos(), blob
, OIDs
, &given_principal
, NULL
) ||
726 status
= ADS_ERROR(LDAP_OPERATIONS_ERROR
);
729 TALLOC_FREE(given_principal
);
731 /* make sure the server understands kerberos */
732 for (i
=0;OIDs
[i
];i
++) {
733 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs
[i
]));
735 if (strcmp(OIDs
[i
], OID_KERBEROS5_OLD
) == 0 ||
736 strcmp(OIDs
[i
], OID_KERBEROS5
) == 0) {
737 got_kerberos_mechanism
= True
;
740 talloc_free(OIDs
[i
]);
743 status
= ads_generate_service_principal(ads
, &p
);
744 if (!ADS_ERR_OK(status
)) {
749 if (!(ads
->auth
.flags
& ADS_AUTH_DISABLE_KERBEROS
) &&
750 got_kerberos_mechanism
)
752 if (ads
->auth
.password
== NULL
||
753 ads
->auth
.password
[0] == '\0')
756 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
757 CRED_MUST_USE_KERBEROS
,
758 p
.service
, p
.hostname
,
760 if (ADS_ERR_OK(status
)) {
761 ads_free_service_principal(&p
);
765 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
766 "calling kinit\n", ads_errstr(status
)));
769 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
771 if (ADS_ERR_OK(status
)) {
772 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
773 CRED_MUST_USE_KERBEROS
,
774 p
.service
, p
.hostname
,
776 if (!ADS_ERR_OK(status
)) {
777 DEBUG(0,("kinit succeeded but "
778 "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
779 ads_errstr(status
)));
783 /* only fallback to NTLMSSP if allowed */
784 if (ADS_ERR_OK(status
) ||
785 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
791 /* lets do NTLMSSP ... this has the big advantage that we don't need
792 to sync clocks, and we don't rely on special versions of the krb5
793 library for HMAC_MD4 encryption */
794 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
795 CRED_DONT_USE_KERBEROS
,
796 p
.service
, p
.hostname
,
799 ads_free_service_principal(&p
);
801 if (blob
.data
!= NULL
) {
802 data_blob_free(&blob
);
808 #define MAX_GSS_PASSES 3
810 /* this performs a SASL/gssapi bind
811 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
812 is very dependent on correctly configured DNS whereas
813 this routine is much less fragile
814 see RFC2078 and RFC2222 for details
816 static ADS_STATUS
ads_sasl_gssapi_do_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
818 uint32_t minor_status
;
819 gss_cred_id_t gss_cred
= GSS_C_NO_CREDENTIAL
;
820 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
821 gss_OID mech_type
= GSS_C_NULL_OID
;
822 gss_buffer_desc output_token
, input_token
;
823 uint32_t req_flags
, ret_flags
;
826 struct berval
*scred
= NULL
;
830 uint32_t max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
831 uint8_t wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
834 input_token
.value
= NULL
;
835 input_token
.length
= 0;
837 status
= ads_init_gssapi_cred(ads
, &gss_cred
);
838 if (!ADS_ERR_OK(status
)) {
843 * Note: here we always ask the gssapi for sign and seal
844 * as this is negotiated later after the mutal
847 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
| GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
849 for (i
=0; i
< MAX_GSS_PASSES
; i
++) {
850 gss_rc
= gss_init_sec_context(&minor_status
,
867 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
868 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
872 cred
.bv_val
= (char *)output_token
.value
;
873 cred
.bv_len
= output_token
.length
;
875 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
877 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
878 status
= ADS_ERROR(rc
);
882 if (output_token
.value
) {
883 gss_release_buffer(&minor_status
, &output_token
);
887 input_token
.value
= scred
->bv_val
;
888 input_token
.length
= scred
->bv_len
;
890 input_token
.value
= NULL
;
891 input_token
.length
= 0;
894 if (gss_rc
== 0) break;
897 gss_rc
= gss_unwrap(&minor_status
,context_handle
,&input_token
,&output_token
,
904 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
908 p
= (uint8_t *)output_token
.value
;
911 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
915 wrap_type
= CVAL(p
,0);
917 max_msg_size
= RIVAL(p
,0);
920 gss_release_buffer(&minor_status
, &output_token
);
922 if (!(wrap_type
& ads
->ldap
.wrap_type
)) {
924 * the server doesn't supports the wrap
927 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
928 ads
->ldap
.wrap_type
, wrap_type
));
929 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
930 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
934 /* 0x58 is the minimum windows accepts */
935 if (max_msg_size
< 0x58) {
939 output_token
.length
= 4;
940 output_token
.value
= SMB_MALLOC(output_token
.length
);
941 if (!output_token
.value
) {
942 output_token
.length
= 0;
943 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
946 p
= (uint8_t *)output_token
.value
;
948 RSIVAL(p
,0,max_msg_size
);
949 SCVAL(p
,0,ads
->ldap
.wrap_type
);
952 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
953 * but using ads->config.bind_path is the wrong! It should be
954 * the DN of the user object!
956 * w2k3 gives an error when we send an incorrect DN, but sending nothing
957 * is ok and matches the information flow used in GSS-SPNEGO.
960 gss_rc
= gss_wrap(&minor_status
, context_handle
,0,GSS_C_QOP_DEFAULT
,
961 &output_token
, /* used as *input* here. */
963 &input_token
); /* Used as *output* here. */
965 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
966 output_token
.length
= 0;
967 SAFE_FREE(output_token
.value
);
971 /* We've finished with output_token. */
972 SAFE_FREE(output_token
.value
);
973 output_token
.length
= 0;
975 cred
.bv_val
= (char *)input_token
.value
;
976 cred
.bv_len
= input_token
.length
;
978 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
980 gss_release_buffer(&minor_status
, &input_token
);
981 status
= ADS_ERROR(rc
);
982 if (!ADS_ERR_OK(status
)) {
986 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
987 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
988 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
990 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
992 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
996 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
997 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
998 ads
->ldap
.in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
999 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
1000 if (!ADS_ERR_OK(status
)) {
1001 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1002 ads_errstr(status
)));
1005 /* make sure we don't free context_handle */
1006 context_handle
= GSS_C_NO_CONTEXT
;
1010 if (gss_cred
!= GSS_C_NO_CREDENTIAL
)
1011 gss_release_cred(&minor_status
, &gss_cred
);
1012 if (context_handle
!= GSS_C_NO_CONTEXT
)
1013 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
1020 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1023 struct ads_service_principal p
;
1025 status
= ads_generate_service_principal(ads
, &p
);
1026 if (!ADS_ERR_OK(status
)) {
1030 if (ads
->auth
.password
== NULL
||
1031 ads
->auth
.password
[0] == '\0') {
1032 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1033 if (ADS_ERR_OK(status
)) {
1034 ads_free_service_principal(&p
);
1038 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1039 "calling kinit\n", ads_errstr(status
)));
1042 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
1044 if (ADS_ERR_OK(status
)) {
1045 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1048 ads_free_service_principal(&p
);
1053 #endif /* HAVE_KRB5 */
1055 /* mapping between SASL mechanisms and functions */
1058 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1059 } sasl_mechanisms
[] = {
1060 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1062 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1067 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1069 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
1075 /* get a list of supported SASL mechanisms */
1076 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
1077 if (!ADS_ERR_OK(status
)) return status
;
1079 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
1081 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
1082 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
1083 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
1084 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1086 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1089 /* try our supported mechanisms in order */
1090 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
1091 /* see if the server supports it */
1092 for (j
=0;values
&& values
[j
];j
++) {
1093 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
1094 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
1096 status
= sasl_mechanisms
[i
].fn(ads
);
1097 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
1098 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
1099 ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
1101 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1102 "retrying with signing enabled\n"));
1103 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1106 ldap_value_free(values
);
1113 ldap_value_free(values
);
1115 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1118 #endif /* HAVE_LDAP */