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 const char *ccache_name
= "MEMORY:ads_sasl_spnego_bind";
753 if (ads
->auth
.ccache_name
!= NULL
) {
754 ccache_name
= ads
->auth
.ccache_name
;
757 if (ads
->auth
.password
== NULL
||
758 ads
->auth
.password
[0] == '\0')
761 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
762 CRED_MUST_USE_KERBEROS
,
763 p
.service
, p
.hostname
,
765 if (ADS_ERR_OK(status
)) {
766 ads_free_service_principal(&p
);
770 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
771 "calling kinit\n", ads_errstr(status
)));
774 setenv(KRB5_ENV_CCNAME
, ccache_name
, 1);
775 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
777 if (ADS_ERR_OK(status
)) {
778 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
779 CRED_MUST_USE_KERBEROS
,
780 p
.service
, p
.hostname
,
782 if (!ADS_ERR_OK(status
)) {
783 DEBUG(0,("kinit succeeded but "
784 "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
785 ads_errstr(status
)));
789 /* only fallback to NTLMSSP if allowed */
790 if (ADS_ERR_OK(status
) ||
791 !(ads
->auth
.flags
& ADS_AUTH_ALLOW_NTLMSSP
)) {
797 /* lets do NTLMSSP ... this has the big advantage that we don't need
798 to sync clocks, and we don't rely on special versions of the krb5
799 library for HMAC_MD4 encryption */
800 status
= ads_sasl_spnego_gensec_bind(ads
, "GSS-SPNEGO",
801 CRED_DONT_USE_KERBEROS
,
802 p
.service
, p
.hostname
,
805 ads_free_service_principal(&p
);
807 if (blob
.data
!= NULL
) {
808 data_blob_free(&blob
);
814 #define MAX_GSS_PASSES 3
816 /* this performs a SASL/gssapi bind
817 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
818 is very dependent on correctly configured DNS whereas
819 this routine is much less fragile
820 see RFC2078 and RFC2222 for details
822 static ADS_STATUS
ads_sasl_gssapi_do_bind(ADS_STRUCT
*ads
, const gss_name_t serv_name
)
824 uint32_t minor_status
;
825 gss_cred_id_t gss_cred
= GSS_C_NO_CREDENTIAL
;
826 gss_ctx_id_t context_handle
= GSS_C_NO_CONTEXT
;
827 gss_OID mech_type
= GSS_C_NULL_OID
;
828 gss_buffer_desc output_token
, input_token
;
829 uint32_t req_flags
, ret_flags
;
832 struct berval
*scred
= NULL
;
836 uint32_t max_msg_size
= ADS_SASL_WRAPPING_OUT_MAX_WRAPPED
;
837 uint8_t wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
840 input_token
.value
= NULL
;
841 input_token
.length
= 0;
843 status
= ads_init_gssapi_cred(ads
, &gss_cred
);
844 if (!ADS_ERR_OK(status
)) {
849 * Note: here we always ask the gssapi for sign and seal
850 * as this is negotiated later after the mutal
853 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
| GSS_C_INTEG_FLAG
| GSS_C_CONF_FLAG
;
855 for (i
=0; i
< MAX_GSS_PASSES
; i
++) {
856 gss_rc
= gss_init_sec_context(&minor_status
,
873 if (gss_rc
&& gss_rc
!= GSS_S_CONTINUE_NEEDED
) {
874 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
878 cred
.bv_val
= (char *)output_token
.value
;
879 cred
.bv_len
= output_token
.length
;
881 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
883 if (rc
!= LDAP_SASL_BIND_IN_PROGRESS
) {
884 status
= ADS_ERROR(rc
);
888 if (output_token
.value
) {
889 gss_release_buffer(&minor_status
, &output_token
);
893 input_token
.value
= scred
->bv_val
;
894 input_token
.length
= scred
->bv_len
;
896 input_token
.value
= NULL
;
897 input_token
.length
= 0;
900 if (gss_rc
== 0) break;
903 gss_rc
= gss_unwrap(&minor_status
,context_handle
,&input_token
,&output_token
,
910 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
914 p
= (uint8_t *)output_token
.value
;
917 file_save("sasl_gssapi.dat", output_token
.value
, output_token
.length
);
921 wrap_type
= CVAL(p
,0);
923 max_msg_size
= RIVAL(p
,0);
926 gss_release_buffer(&minor_status
, &output_token
);
928 if (!(wrap_type
& ads
->ldap
.wrap_type
)) {
930 * the server doesn't supports the wrap
933 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
934 ads
->ldap
.wrap_type
, wrap_type
));
935 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
936 status
= ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
940 /* 0x58 is the minimum windows accepts */
941 if (max_msg_size
< 0x58) {
945 output_token
.length
= 4;
946 output_token
.value
= SMB_MALLOC(output_token
.length
);
947 if (!output_token
.value
) {
948 output_token
.length
= 0;
949 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
952 p
= (uint8_t *)output_token
.value
;
954 RSIVAL(p
,0,max_msg_size
);
955 SCVAL(p
,0,ads
->ldap
.wrap_type
);
958 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
959 * but using ads->config.bind_path is the wrong! It should be
960 * the DN of the user object!
962 * w2k3 gives an error when we send an incorrect DN, but sending nothing
963 * is ok and matches the information flow used in GSS-SPNEGO.
966 gss_rc
= gss_wrap(&minor_status
, context_handle
,0,GSS_C_QOP_DEFAULT
,
967 &output_token
, /* used as *input* here. */
969 &input_token
); /* Used as *output* here. */
971 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
972 output_token
.length
= 0;
973 SAFE_FREE(output_token
.value
);
977 /* We've finished with output_token. */
978 SAFE_FREE(output_token
.value
);
979 output_token
.length
= 0;
981 cred
.bv_val
= (char *)input_token
.value
;
982 cred
.bv_len
= input_token
.length
;
984 rc
= ldap_sasl_bind_s(ads
->ldap
.ld
, NULL
, "GSSAPI", &cred
, NULL
, NULL
,
986 gss_release_buffer(&minor_status
, &input_token
);
987 status
= ADS_ERROR(rc
);
988 if (!ADS_ERR_OK(status
)) {
992 if (ads
->ldap
.wrap_type
> ADS_SASLWRAP_TYPE_PLAIN
) {
993 gss_rc
= gss_wrap_size_limit(&minor_status
, context_handle
,
994 (ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_SEAL
),
996 max_msg_size
, &ads
->ldap
.out
.max_unwrapped
);
998 status
= ADS_ERROR_GSS(gss_rc
, minor_status
);
1002 ads
->ldap
.out
.sig_size
= max_msg_size
- ads
->ldap
.out
.max_unwrapped
;
1003 ads
->ldap
.in
.min_wrapped
= 0x2C; /* taken from a capture with LDAP unbind */
1004 ads
->ldap
.in
.max_wrapped
= ADS_SASL_WRAPPING_IN_MAX_WRAPPED
;
1005 status
= ads_setup_sasl_wrapping(ads
, &ads_sasl_gssapi_ops
, context_handle
);
1006 if (!ADS_ERR_OK(status
)) {
1007 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1008 ads_errstr(status
)));
1011 /* make sure we don't free context_handle */
1012 context_handle
= GSS_C_NO_CONTEXT
;
1016 if (gss_cred
!= GSS_C_NO_CREDENTIAL
)
1017 gss_release_cred(&minor_status
, &gss_cred
);
1018 if (context_handle
!= GSS_C_NO_CONTEXT
)
1019 gss_delete_sec_context(&minor_status
, &context_handle
, GSS_C_NO_BUFFER
);
1026 static ADS_STATUS
ads_sasl_gssapi_bind(ADS_STRUCT
*ads
)
1029 struct ads_service_principal p
;
1030 const char *ccache_name
= "MEMORY:ads_sasl_gssapi_do_bind";
1032 status
= ads_generate_service_principal(ads
, &p
);
1033 if (!ADS_ERR_OK(status
)) {
1037 if (ads
->auth
.password
== NULL
||
1038 ads
->auth
.password
[0] == '\0') {
1039 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1040 if (ADS_ERR_OK(status
)) {
1041 ads_free_service_principal(&p
);
1045 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1046 "calling kinit\n", ads_errstr(status
)));
1049 if (ads
->auth
.ccache_name
!= NULL
) {
1050 ccache_name
= ads
->auth
.ccache_name
;
1052 setenv(KRB5_ENV_CCNAME
, ccache_name
, 1);
1053 status
= ADS_ERROR_KRB5(ads_kinit_password(ads
));
1055 if (ADS_ERR_OK(status
)) {
1056 status
= ads_sasl_gssapi_do_bind(ads
, p
.name
);
1059 ads_free_service_principal(&p
);
1064 #endif /* HAVE_KRB5 */
1066 /* mapping between SASL mechanisms and functions */
1069 ADS_STATUS (*fn
)(ADS_STRUCT
*);
1070 } sasl_mechanisms
[] = {
1071 {"GSS-SPNEGO", ads_sasl_spnego_bind
},
1073 {"GSSAPI", ads_sasl_gssapi_bind
}, /* doesn't work with .NET RC1. No idea why */
1078 ADS_STATUS
ads_sasl_bind(ADS_STRUCT
*ads
)
1080 const char *attrs
[] = {"supportedSASLMechanisms", NULL
};
1086 /* get a list of supported SASL mechanisms */
1087 status
= ads_do_search(ads
, "", LDAP_SCOPE_BASE
, "(objectclass=*)", attrs
, &res
);
1088 if (!ADS_ERR_OK(status
)) return status
;
1090 values
= ldap_get_values(ads
->ldap
.ld
, res
, "supportedSASLMechanisms");
1092 if (ads
->auth
.flags
& ADS_AUTH_SASL_SEAL
) {
1093 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SEAL
;
1094 } else if (ads
->auth
.flags
& ADS_AUTH_SASL_SIGN
) {
1095 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1097 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_PLAIN
;
1100 /* try our supported mechanisms in order */
1101 for (i
=0;sasl_mechanisms
[i
].name
;i
++) {
1102 /* see if the server supports it */
1103 for (j
=0;values
&& values
[j
];j
++) {
1104 if (strcmp(values
[j
], sasl_mechanisms
[i
].name
) == 0) {
1105 DEBUG(4,("Found SASL mechanism %s\n", values
[j
]));
1107 status
= sasl_mechanisms
[i
].fn(ads
);
1108 if (status
.error_type
== ENUM_ADS_ERROR_LDAP
&&
1109 status
.err
.rc
== LDAP_STRONG_AUTH_REQUIRED
&&
1110 ads
->ldap
.wrap_type
== ADS_SASLWRAP_TYPE_PLAIN
)
1112 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1113 "retrying with signing enabled\n"));
1114 ads
->ldap
.wrap_type
= ADS_SASLWRAP_TYPE_SIGN
;
1117 ldap_value_free(values
);
1124 ldap_value_free(values
);
1126 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED
);
1129 #endif /* HAVE_LDAP */