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"
32 static ADS_STATUS ads_sasl_gensec_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
34 struct gensec_security *gensec_security =
35 talloc_get_type_abort(ads->ldap.wrap_private_data,
36 struct gensec_security);
38 DATA_BLOB unwrapped, wrapped;
39 TALLOC_CTX *frame = talloc_stackframe();
41 unwrapped = data_blob_const(buf, len);
43 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
44 if (!NT_STATUS_IS_OK(nt_status)) {
46 return ADS_ERROR_NT(nt_status);
49 if ((ads->ldap.out.size - 4) < wrapped.length) {
51 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
54 /* copy the wrapped blob to the right location */
55 memcpy(ads->ldap.out.buf + 4, wrapped.data, wrapped.length);
57 /* set how many bytes must be written to the underlying socket */
58 ads->ldap.out.left = 4 + wrapped.length;
65 static ADS_STATUS ads_sasl_gensec_unwrap(ADS_STRUCT *ads)
67 struct gensec_security *gensec_security =
68 talloc_get_type_abort(ads->ldap.wrap_private_data,
69 struct gensec_security);
71 DATA_BLOB unwrapped, wrapped;
72 TALLOC_CTX *frame = talloc_stackframe();
74 wrapped = data_blob_const(ads->ldap.in.buf + 4, ads->ldap.in.ofs - 4);
76 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
77 if (!NT_STATUS_IS_OK(nt_status)) {
79 return ADS_ERROR_NT(nt_status);
82 if (wrapped.length < unwrapped.length) {
84 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
87 /* copy the wrapped blob to the right location */
88 memcpy(ads->ldap.in.buf + 4, unwrapped.data, unwrapped.length);
90 /* set how many bytes must be written to the underlying socket */
91 ads->ldap.in.left = unwrapped.length;
99 static void ads_sasl_gensec_disconnect(ADS_STRUCT *ads)
101 struct gensec_security *gensec_security =
102 talloc_get_type_abort(ads->ldap.wrap_private_data,
103 struct gensec_security);
105 TALLOC_FREE(gensec_security);
107 ads->ldap.wrap_ops = NULL;
108 ads->ldap.wrap_private_data = NULL;
111 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
113 .wrap = ads_sasl_gensec_wrap,
114 .unwrap = ads_sasl_gensec_unwrap,
115 .disconnect = ads_sasl_gensec_disconnect
119 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
120 we fit on one socket??)
122 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
124 enum credentials_use_kerberos krb5_state,
125 const char *target_service,
126 const char *target_hostname,
127 const DATA_BLOB server_blob)
129 DATA_BLOB blob_in = data_blob_null;
130 DATA_BLOB blob_out = data_blob_null;
134 struct auth_generic_state *auth_generic_state;
135 bool use_spnego_principal = lp_client_use_spnego_principal();
136 const char *sasl_list[] = { sasl, NULL };
139 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
140 if (!NT_STATUS_IS_OK(nt_status)) {
141 return ADS_ERROR_NT(nt_status);
144 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
145 return ADS_ERROR_NT(nt_status);
147 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
148 return ADS_ERROR_NT(nt_status);
150 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
151 return ADS_ERROR_NT(nt_status);
154 if (server_blob.length == 0) {
155 use_spnego_principal = false;
158 if (krb5_state == CRED_DONT_USE_KERBEROS) {
159 use_spnego_principal = false;
162 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
165 if (target_service != NULL) {
166 nt_status = gensec_set_target_service(
167 auth_generic_state->gensec_security,
169 if (!NT_STATUS_IS_OK(nt_status)) {
170 return ADS_ERROR_NT(nt_status);
174 if (target_hostname != NULL) {
175 nt_status = gensec_set_target_hostname(
176 auth_generic_state->gensec_security,
178 if (!NT_STATUS_IS_OK(nt_status)) {
179 return ADS_ERROR_NT(nt_status);
183 if (target_service != NULL && target_hostname != NULL) {
184 use_spnego_principal = false;
187 switch (ads->ldap.wrap_type) {
188 case ADS_SASLWRAP_TYPE_SEAL:
189 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
190 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
192 case ADS_SASLWRAP_TYPE_SIGN:
193 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
194 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
197 * windows servers are broken with sign only,
198 * so we let the NTLMSSP backend to seal here,
199 * via GENSEC_FEATURE_LDAP_STYLE.
201 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
202 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
205 case ADS_SASLWRAP_TYPE_PLAIN:
209 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
211 if (!NT_STATUS_IS_OK(nt_status)) {
212 return ADS_ERROR_NT(nt_status);
215 rc = LDAP_SASL_BIND_IN_PROGRESS;
216 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
217 if (use_spnego_principal) {
218 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
219 if (blob_in.length == 0) {
220 TALLOC_FREE(auth_generic_state);
221 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
224 blob_in = data_blob_null;
226 blob_out = data_blob_null;
229 struct berval cred, *scred = NULL;
231 nt_status = gensec_update(auth_generic_state->gensec_security,
232 talloc_tos(), blob_in, &blob_out);
233 data_blob_free(&blob_in);
234 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
235 && !NT_STATUS_IS_OK(nt_status))
237 TALLOC_FREE(auth_generic_state);
238 data_blob_free(&blob_out);
239 return ADS_ERROR_NT(nt_status);
242 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
246 cred.bv_val = (char *)blob_out.data;
247 cred.bv_len = blob_out.length;
249 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
250 data_blob_free(&blob_out);
251 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
256 TALLOC_FREE(auth_generic_state);
257 return ADS_ERROR(rc);
260 blob_in = data_blob_talloc(talloc_tos(),
263 if (blob_in.length != scred->bv_len) {
265 TALLOC_FREE(auth_generic_state);
266 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
270 blob_in = data_blob_null;
272 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
277 data_blob_free(&blob_in);
278 data_blob_free(&blob_out);
280 if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
283 ok = gensec_have_feature(auth_generic_state->gensec_security,
284 GENSEC_FEATURE_SEAL);
286 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
287 TALLOC_FREE(auth_generic_state);
288 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
291 ok = gensec_have_feature(auth_generic_state->gensec_security,
292 GENSEC_FEATURE_SIGN);
294 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
295 TALLOC_FREE(auth_generic_state);
296 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
299 } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
302 ok = gensec_have_feature(auth_generic_state->gensec_security,
303 GENSEC_FEATURE_SIGN);
305 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
306 TALLOC_FREE(auth_generic_state);
307 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
311 ads->auth.tgs_expire = LONG_MAX;
312 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
313 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
315 nttime_to_timeval(&tv, end_nt_time);
316 ads->auth.tgs_expire = tv.tv_sec;
319 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
320 size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
321 ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
323 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
325 * Note that we have to truncate this to 0x2C
326 * (taken from a capture with LDAP unbind), as the
327 * signature size is not constant for Kerberos with
330 ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C);
331 ads->ldap.in.max_wrapped = max_wrapped;
332 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security);
333 if (!ADS_ERR_OK(status)) {
334 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
335 ads_errstr(status)));
336 TALLOC_FREE(auth_generic_state);
339 /* Only keep the gensec_security element around long-term */
340 talloc_steal(NULL, auth_generic_state->gensec_security);
342 TALLOC_FREE(auth_generic_state);
344 return ADS_ERROR(rc);
348 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
352 krb5_error_code kerr;
353 krb5_ccache kccache = NULL;
356 *cred = GSS_C_NO_CREDENTIAL;
358 if (!ads->auth.ccache_name) {
362 kerr = krb5_init_context(&kctx);
364 return ADS_ERROR_KRB5(kerr);
367 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
368 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
370 status = ADS_ERROR_KRB5(kerr);
374 maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
375 if (maj != GSS_S_COMPLETE) {
376 status = ADS_ERROR_GSS(maj, min);
380 /* We need to fallback to overriding the default creds.
381 * This operation is not thread safe as it changes the process
382 * environment variable, but we do not have any better option
383 * with older kerberos libraries */
385 const char *oldccname = NULL;
387 oldccname = getenv("KRB5CCNAME");
388 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
390 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
391 NULL, GSS_C_INITIATE, cred, NULL, NULL);
394 setenv("KRB5CCNAME", oldccname, 1);
396 unsetenv("KRB5CCNAME");
399 if (maj != GSS_S_COMPLETE) {
400 status = ADS_ERROR_GSS(maj, min);
406 status = ADS_SUCCESS;
409 if (!ADS_ERR_OK(status) && kccache != NULL) {
410 krb5_cc_close(kctx, kccache);
412 krb5_free_context(kctx);
416 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
418 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
421 uint32_t minor_status;
422 gss_buffer_desc unwrapped, wrapped;
423 int conf_req_flag, conf_state;
425 unwrapped.value = buf;
426 unwrapped.length = len;
428 /* for now request sign and seal */
429 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
431 gss_rc = gss_wrap(&minor_status, context_handle,
432 conf_req_flag, GSS_C_QOP_DEFAULT,
433 &unwrapped, &conf_state,
435 status = ADS_ERROR_GSS(gss_rc, minor_status);
436 if (!ADS_ERR_OK(status)) return status;
438 if (conf_req_flag && conf_state == 0) {
439 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
442 if ((ads->ldap.out.size - 4) < wrapped.length) {
443 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
446 /* copy the wrapped blob to the right location */
447 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
449 /* set how many bytes must be written to the underlying socket */
450 ads->ldap.out.left = 4 + wrapped.length;
452 gss_release_buffer(&minor_status, &wrapped);
457 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
459 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
462 uint32_t minor_status;
463 gss_buffer_desc unwrapped, wrapped;
466 wrapped.value = ads->ldap.in.buf + 4;
467 wrapped.length = ads->ldap.in.ofs - 4;
469 gss_rc = gss_unwrap(&minor_status, context_handle,
470 &wrapped, &unwrapped,
471 &conf_state, GSS_C_QOP_DEFAULT);
472 status = ADS_ERROR_GSS(gss_rc, minor_status);
473 if (!ADS_ERR_OK(status)) return status;
475 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
476 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
479 if (wrapped.length < unwrapped.length) {
480 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
483 /* copy the wrapped blob to the right location */
484 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
486 /* set how many bytes must be written to the underlying socket */
487 ads->ldap.in.left = unwrapped.length;
488 ads->ldap.in.ofs = 4;
490 gss_release_buffer(&minor_status, &unwrapped);
495 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
497 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
498 uint32_t minor_status;
500 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
502 ads->ldap.wrap_ops = NULL;
503 ads->ldap.wrap_private_data = NULL;
506 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
508 .wrap = ads_sasl_gssapi_wrap,
509 .unwrap = ads_sasl_gssapi_unwrap,
510 .disconnect = ads_sasl_gssapi_disconnect
513 #endif /* HAVE_KRB5 */
516 struct ads_service_principal {
525 static void ads_free_service_principal(struct ads_service_principal *p)
527 SAFE_FREE(p->service);
528 SAFE_FREE(p->hostname);
529 SAFE_FREE(p->string);
533 uint32_t minor_status;
534 gss_release_name(&minor_status, &p->name);
540 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
545 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
552 frame = talloc_stackframe();
554 return ADS_ERROR(LDAP_NO_MEMORY);
557 if (ads->server.realm && ads->server.ldap_server) {
558 server = strlower_talloc(frame, ads->server.ldap_server);
559 if (server == NULL) {
563 realm = strupper_talloc(frame, ads->server.realm);
569 * If we got a name which is bigger than a NetBIOS name,
570 * but isn't a FQDN, create one.
572 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
575 dnsdomain = strlower_talloc(frame, ads->server.realm);
576 if (dnsdomain == NULL) {
580 server = talloc_asprintf(frame,
583 if (server == NULL) {
587 } else if (ads->config.realm && ads->config.ldap_server_name) {
588 server = strlower_talloc(frame, ads->config.ldap_server_name);
589 if (server == NULL) {
593 realm = strupper_talloc(frame, ads->config.realm);
599 * If we got a name which is bigger than a NetBIOS name,
600 * but isn't a FQDN, create one.
602 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
605 dnsdomain = strlower_talloc(frame, ads->server.realm);
606 if (dnsdomain == NULL) {
610 server = talloc_asprintf(frame,
613 if (server == NULL) {
619 if (server == NULL || realm == NULL) {
623 *service = SMB_STRDUP("ldap");
624 if (*service == NULL) {
625 status = ADS_ERROR(LDAP_PARAM_ERROR);
628 *hostname = SMB_STRDUP(server);
629 if (*hostname == NULL) {
631 status = ADS_ERROR(LDAP_PARAM_ERROR);
634 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
635 if (rc == -1 || princ == NULL) {
637 SAFE_FREE(*hostname);
638 status = ADS_ERROR(LDAP_PARAM_ERROR);
644 status = ADS_SUCCESS;
650 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
651 struct ads_service_principal *p)
655 gss_buffer_desc input_name;
656 /* GSS_KRB5_NT_PRINCIPAL_NAME */
657 gss_OID_desc nt_principal =
658 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
659 uint32_t minor_status;
665 status = ads_guess_target(ads,
669 if (!ADS_ERR_OK(status)) {
674 input_name.value = p->string;
675 input_name.length = strlen(p->string);
677 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
679 ads_free_service_principal(p);
680 return ADS_ERROR_GSS(gss_rc, minor_status);
687 #endif /* HAVE_KRB5 */
690 this performs a SASL/SPNEGO bind
692 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
694 TALLOC_CTX *frame = talloc_stackframe();
695 struct ads_service_principal p = {0};
696 struct berval *scred=NULL;
700 char *given_principal = NULL;
701 char *OIDs[ASN1_MAX_OIDS];
703 bool got_kerberos_mechanism = False;
706 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
708 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
709 status = ADS_ERROR(rc);
713 blob = data_blob(scred->bv_val, scred->bv_len);
718 file_save("sasl_spnego.dat", blob.data, blob.length);
721 /* the server sent us the first part of the SPNEGO exchange in the negprot
723 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
725 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
728 TALLOC_FREE(given_principal);
730 /* make sure the server understands kerberos */
731 for (i=0;OIDs[i];i++) {
732 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
734 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
735 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
736 got_kerberos_mechanism = True;
739 talloc_free(OIDs[i]);
742 status = ads_generate_service_principal(ads, &p);
743 if (!ADS_ERR_OK(status)) {
748 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
749 got_kerberos_mechanism)
751 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
752 CRED_MUST_USE_KERBEROS,
753 p.service, p.hostname,
755 if (ADS_ERR_OK(status)) {
756 ads_free_service_principal(&p);
760 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
761 "calling kinit\n", ads_errstr(status)));
763 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
765 if (ADS_ERR_OK(status)) {
766 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
767 CRED_MUST_USE_KERBEROS,
768 p.service, p.hostname,
770 if (!ADS_ERR_OK(status)) {
771 DEBUG(0,("kinit succeeded but "
772 "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
773 ads_errstr(status)));
777 /* only fallback to NTLMSSP if allowed */
778 if (ADS_ERR_OK(status) ||
779 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
785 /* lets do NTLMSSP ... this has the big advantage that we don't need
786 to sync clocks, and we don't rely on special versions of the krb5
787 library for HMAC_MD4 encryption */
788 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
789 CRED_DONT_USE_KERBEROS,
790 p.service, p.hostname,
793 ads_free_service_principal(&p);
799 #define MAX_GSS_PASSES 3
801 /* this performs a SASL/gssapi bind
802 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
803 is very dependent on correctly configured DNS whereas
804 this routine is much less fragile
805 see RFC2078 and RFC2222 for details
807 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
809 uint32_t minor_status;
810 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
811 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
812 gss_OID mech_type = GSS_C_NULL_OID;
813 gss_buffer_desc output_token, input_token;
814 uint32_t req_flags, ret_flags;
817 struct berval *scred = NULL;
821 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
822 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
825 input_token.value = NULL;
826 input_token.length = 0;
828 status = ads_init_gssapi_cred(ads, &gss_cred);
829 if (!ADS_ERR_OK(status)) {
834 * Note: here we always ask the gssapi for sign and seal
835 * as this is negotiated later after the mutal
838 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
840 for (i=0; i < MAX_GSS_PASSES; i++) {
841 gss_rc = gss_init_sec_context(&minor_status,
858 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
859 status = ADS_ERROR_GSS(gss_rc, minor_status);
863 cred.bv_val = (char *)output_token.value;
864 cred.bv_len = output_token.length;
866 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
868 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
869 status = ADS_ERROR(rc);
873 if (output_token.value) {
874 gss_release_buffer(&minor_status, &output_token);
878 input_token.value = scred->bv_val;
879 input_token.length = scred->bv_len;
881 input_token.value = NULL;
882 input_token.length = 0;
885 if (gss_rc == 0) break;
888 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
895 status = ADS_ERROR_GSS(gss_rc, minor_status);
899 p = (uint8_t *)output_token.value;
902 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
906 wrap_type = CVAL(p,0);
908 max_msg_size = RIVAL(p,0);
911 gss_release_buffer(&minor_status, &output_token);
913 if (!(wrap_type & ads->ldap.wrap_type)) {
915 * the server doesn't supports the wrap
918 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
919 ads->ldap.wrap_type, wrap_type));
920 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
921 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
925 /* 0x58 is the minimum windows accepts */
926 if (max_msg_size < 0x58) {
930 output_token.length = 4;
931 output_token.value = SMB_MALLOC(output_token.length);
932 if (!output_token.value) {
933 output_token.length = 0;
934 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
937 p = (uint8_t *)output_token.value;
939 RSIVAL(p,0,max_msg_size);
940 SCVAL(p,0,ads->ldap.wrap_type);
943 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
944 * but using ads->config.bind_path is the wrong! It should be
945 * the DN of the user object!
947 * w2k3 gives an error when we send an incorrect DN, but sending nothing
948 * is ok and matches the information flow used in GSS-SPNEGO.
951 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
952 &output_token, /* used as *input* here. */
954 &input_token); /* Used as *output* here. */
956 status = ADS_ERROR_GSS(gss_rc, minor_status);
957 output_token.length = 0;
958 SAFE_FREE(output_token.value);
962 /* We've finished with output_token. */
963 SAFE_FREE(output_token.value);
964 output_token.length = 0;
966 cred.bv_val = (char *)input_token.value;
967 cred.bv_len = input_token.length;
969 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
971 gss_release_buffer(&minor_status, &input_token);
972 status = ADS_ERROR(rc);
973 if (!ADS_ERR_OK(status)) {
977 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
978 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
979 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
981 max_msg_size, &ads->ldap.out.max_unwrapped);
983 status = ADS_ERROR_GSS(gss_rc, minor_status);
987 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
988 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
989 ads->ldap.in.max_wrapped = max_msg_size;
990 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
991 if (!ADS_ERR_OK(status)) {
992 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
993 ads_errstr(status)));
996 /* make sure we don't free context_handle */
997 context_handle = GSS_C_NO_CONTEXT;
1001 if (gss_cred != GSS_C_NO_CREDENTIAL)
1002 gss_release_cred(&minor_status, &gss_cred);
1003 if (context_handle != GSS_C_NO_CONTEXT)
1004 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1011 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1014 struct ads_service_principal p;
1016 status = ads_generate_service_principal(ads, &p);
1017 if (!ADS_ERR_OK(status)) {
1021 status = ads_sasl_gssapi_do_bind(ads, p.name);
1022 if (ADS_ERR_OK(status)) {
1023 ads_free_service_principal(&p);
1027 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1028 "calling kinit\n", ads_errstr(status)));
1030 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1032 if (ADS_ERR_OK(status)) {
1033 status = ads_sasl_gssapi_do_bind(ads, p.name);
1036 ads_free_service_principal(&p);
1041 #endif /* HAVE_KRB5 */
1043 /* mapping between SASL mechanisms and functions */
1046 ADS_STATUS (*fn)(ADS_STRUCT *);
1047 } sasl_mechanisms[] = {
1048 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1050 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1055 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1057 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1063 /* get a list of supported SASL mechanisms */
1064 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1065 if (!ADS_ERR_OK(status)) return status;
1067 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1069 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1070 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1071 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1072 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1074 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1077 /* try our supported mechanisms in order */
1078 for (i=0;sasl_mechanisms[i].name;i++) {
1079 /* see if the server supports it */
1080 for (j=0;values && values[j];j++) {
1081 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1082 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1084 status = sasl_mechanisms[i].fn(ads);
1085 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1086 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1087 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1089 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1090 "retrying with signing enabled\n"));
1091 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1094 ldap_value_free(values);
1101 ldap_value_free(values);
1103 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1106 #endif /* HAVE_LDAP */