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 };
138 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
139 if (!NT_STATUS_IS_OK(nt_status)) {
140 return ADS_ERROR_NT(nt_status);
143 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
144 return ADS_ERROR_NT(nt_status);
146 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
147 return ADS_ERROR_NT(nt_status);
149 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
150 return ADS_ERROR_NT(nt_status);
153 if (server_blob.length == 0) {
154 use_spnego_principal = false;
157 if (krb5_state == CRED_DONT_USE_KERBEROS) {
158 use_spnego_principal = false;
161 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
164 if (target_service != NULL) {
165 nt_status = gensec_set_target_service(
166 auth_generic_state->gensec_security,
168 if (!NT_STATUS_IS_OK(nt_status)) {
169 return ADS_ERROR_NT(nt_status);
173 if (target_hostname != NULL) {
174 nt_status = gensec_set_target_hostname(
175 auth_generic_state->gensec_security,
177 if (!NT_STATUS_IS_OK(nt_status)) {
178 return ADS_ERROR_NT(nt_status);
182 if (target_service != NULL && target_hostname != NULL) {
183 use_spnego_principal = false;
186 switch (ads->ldap.wrap_type) {
187 case ADS_SASLWRAP_TYPE_SEAL:
188 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
189 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
191 case ADS_SASLWRAP_TYPE_SIGN:
192 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
193 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
196 * windows servers are broken with sign only,
197 * so we let the NTLMSSP backend to seal here,
198 * via GENSEC_FEATURE_LDAP_STYLE.
200 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
201 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
204 case ADS_SASLWRAP_TYPE_PLAIN:
208 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
210 if (!NT_STATUS_IS_OK(nt_status)) {
211 return ADS_ERROR_NT(nt_status);
214 rc = LDAP_SASL_BIND_IN_PROGRESS;
215 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
216 if (use_spnego_principal) {
217 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
218 if (blob_in.length == 0) {
219 TALLOC_FREE(auth_generic_state);
220 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
223 blob_in = data_blob_null;
225 blob_out = data_blob_null;
228 struct berval cred, *scred = NULL;
230 nt_status = gensec_update(auth_generic_state->gensec_security,
231 talloc_tos(), blob_in, &blob_out);
232 data_blob_free(&blob_in);
233 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
234 && !NT_STATUS_IS_OK(nt_status))
236 TALLOC_FREE(auth_generic_state);
237 data_blob_free(&blob_out);
238 return ADS_ERROR_NT(nt_status);
241 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
245 cred.bv_val = (char *)blob_out.data;
246 cred.bv_len = blob_out.length;
248 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
249 data_blob_free(&blob_out);
250 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
255 TALLOC_FREE(auth_generic_state);
256 return ADS_ERROR(rc);
259 blob_in = data_blob_talloc(talloc_tos(),
262 if (blob_in.length != scred->bv_len) {
264 TALLOC_FREE(auth_generic_state);
265 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
269 blob_in = data_blob_null;
271 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
276 data_blob_free(&blob_in);
277 data_blob_free(&blob_out);
279 if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
282 ok = gensec_have_feature(auth_generic_state->gensec_security,
283 GENSEC_FEATURE_SEAL);
285 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
286 TALLOC_FREE(auth_generic_state);
287 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
290 ok = gensec_have_feature(auth_generic_state->gensec_security,
291 GENSEC_FEATURE_SIGN);
293 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
294 TALLOC_FREE(auth_generic_state);
295 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
298 } else if (ads->ldap.wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
301 ok = gensec_have_feature(auth_generic_state->gensec_security,
302 GENSEC_FEATURE_SIGN);
304 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
305 TALLOC_FREE(auth_generic_state);
306 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
310 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
311 size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security);
312 ads->ldap.out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security);
314 ads->ldap.out.sig_size = max_wrapped - ads->ldap.out.max_unwrapped;
316 * Note that we have to truncate this to 0x2C
317 * (taken from a capture with LDAP unbind), as the
318 * signature size is not constant for Kerberos with
321 ads->ldap.in.min_wrapped = MIN(ads->ldap.out.sig_size, 0x2C);
322 ads->ldap.in.max_wrapped = max_wrapped;
323 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gensec_ops, auth_generic_state->gensec_security);
324 if (!ADS_ERR_OK(status)) {
325 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
326 ads_errstr(status)));
327 TALLOC_FREE(auth_generic_state);
330 /* Only keep the gensec_security element around long-term */
331 talloc_steal(NULL, auth_generic_state->gensec_security);
333 TALLOC_FREE(auth_generic_state);
335 return ADS_ERROR(rc);
339 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
343 krb5_error_code kerr;
344 krb5_ccache kccache = NULL;
347 *cred = GSS_C_NO_CREDENTIAL;
349 if (!ads->auth.ccache_name) {
353 kerr = krb5_init_context(&kctx);
355 return ADS_ERROR_KRB5(kerr);
358 #ifdef HAVE_GSS_KRB5_IMPORT_CRED
359 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
361 status = ADS_ERROR_KRB5(kerr);
365 maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
366 if (maj != GSS_S_COMPLETE) {
367 status = ADS_ERROR_GSS(maj, min);
371 /* We need to fallback to overriding the default creds.
372 * This operation is not thread safe as it changes the process
373 * environment variable, but we do not have any better option
374 * with older kerberos libraries */
376 const char *oldccname = NULL;
378 oldccname = getenv("KRB5CCNAME");
379 setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
381 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
382 NULL, GSS_C_INITIATE, cred, NULL, NULL);
385 setenv("KRB5CCNAME", oldccname, 1);
387 unsetenv("KRB5CCNAME");
390 if (maj != GSS_S_COMPLETE) {
391 status = ADS_ERROR_GSS(maj, min);
397 status = ADS_SUCCESS;
400 if (!ADS_ERR_OK(status) && kccache != NULL) {
401 krb5_cc_close(kctx, kccache);
403 krb5_free_context(kctx);
407 static ADS_STATUS ads_sasl_gssapi_wrap(ADS_STRUCT *ads, uint8_t *buf, uint32_t len)
409 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
412 uint32_t minor_status;
413 gss_buffer_desc unwrapped, wrapped;
414 int conf_req_flag, conf_state;
416 unwrapped.value = buf;
417 unwrapped.length = len;
419 /* for now request sign and seal */
420 conf_req_flag = (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL);
422 gss_rc = gss_wrap(&minor_status, context_handle,
423 conf_req_flag, GSS_C_QOP_DEFAULT,
424 &unwrapped, &conf_state,
426 status = ADS_ERROR_GSS(gss_rc, minor_status);
427 if (!ADS_ERR_OK(status)) return status;
429 if (conf_req_flag && conf_state == 0) {
430 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
433 if ((ads->ldap.out.size - 4) < wrapped.length) {
434 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
437 /* copy the wrapped blob to the right location */
438 memcpy(ads->ldap.out.buf + 4, wrapped.value, wrapped.length);
440 /* set how many bytes must be written to the underlying socket */
441 ads->ldap.out.left = 4 + wrapped.length;
443 gss_release_buffer(&minor_status, &wrapped);
448 static ADS_STATUS ads_sasl_gssapi_unwrap(ADS_STRUCT *ads)
450 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
453 uint32_t minor_status;
454 gss_buffer_desc unwrapped, wrapped;
457 wrapped.value = ads->ldap.in.buf + 4;
458 wrapped.length = ads->ldap.in.ofs - 4;
460 gss_rc = gss_unwrap(&minor_status, context_handle,
461 &wrapped, &unwrapped,
462 &conf_state, GSS_C_QOP_DEFAULT);
463 status = ADS_ERROR_GSS(gss_rc, minor_status);
464 if (!ADS_ERR_OK(status)) return status;
466 if (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
467 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
470 if (wrapped.length < unwrapped.length) {
471 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
474 /* copy the wrapped blob to the right location */
475 memcpy(ads->ldap.in.buf + 4, unwrapped.value, unwrapped.length);
477 /* set how many bytes must be written to the underlying socket */
478 ads->ldap.in.left = unwrapped.length;
479 ads->ldap.in.ofs = 4;
481 gss_release_buffer(&minor_status, &unwrapped);
486 static void ads_sasl_gssapi_disconnect(ADS_STRUCT *ads)
488 gss_ctx_id_t context_handle = (gss_ctx_id_t)ads->ldap.wrap_private_data;
489 uint32_t minor_status;
491 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
493 ads->ldap.wrap_ops = NULL;
494 ads->ldap.wrap_private_data = NULL;
497 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
499 .wrap = ads_sasl_gssapi_wrap,
500 .unwrap = ads_sasl_gssapi_unwrap,
501 .disconnect = ads_sasl_gssapi_disconnect
504 #endif /* HAVE_KRB5 */
507 struct ads_service_principal {
516 static void ads_free_service_principal(struct ads_service_principal *p)
518 SAFE_FREE(p->service);
519 SAFE_FREE(p->hostname);
520 SAFE_FREE(p->string);
524 uint32_t minor_status;
525 gss_release_name(&minor_status, &p->name);
531 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
536 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
543 frame = talloc_stackframe();
545 return ADS_ERROR(LDAP_NO_MEMORY);
548 if (ads->server.realm && ads->server.ldap_server) {
549 server = strlower_talloc(frame, ads->server.ldap_server);
550 if (server == NULL) {
554 realm = strupper_talloc(frame, ads->server.realm);
560 * If we got a name which is bigger than a NetBIOS name,
561 * but isn't a FQDN, create one.
563 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
566 dnsdomain = strlower_talloc(frame, ads->server.realm);
567 if (dnsdomain == NULL) {
571 server = talloc_asprintf(frame,
574 if (server == NULL) {
578 } else if (ads->config.realm && ads->config.ldap_server_name) {
579 server = strlower_talloc(frame, ads->config.ldap_server_name);
580 if (server == NULL) {
584 realm = strupper_talloc(frame, ads->config.realm);
590 * If we got a name which is bigger than a NetBIOS name,
591 * but isn't a FQDN, create one.
593 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
596 dnsdomain = strlower_talloc(frame, ads->server.realm);
597 if (dnsdomain == NULL) {
601 server = talloc_asprintf(frame,
604 if (server == NULL) {
610 if (server == NULL || realm == NULL) {
614 *service = SMB_STRDUP("ldap");
615 if (*service == NULL) {
616 status = ADS_ERROR(LDAP_PARAM_ERROR);
619 *hostname = SMB_STRDUP(server);
620 if (*hostname == NULL) {
622 status = ADS_ERROR(LDAP_PARAM_ERROR);
625 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
626 if (rc == -1 || princ == NULL) {
628 SAFE_FREE(*hostname);
629 status = ADS_ERROR(LDAP_PARAM_ERROR);
635 status = ADS_SUCCESS;
641 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
642 struct ads_service_principal *p)
646 gss_buffer_desc input_name;
647 /* GSS_KRB5_NT_PRINCIPAL_NAME */
648 gss_OID_desc nt_principal =
649 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
650 uint32_t minor_status;
656 status = ads_guess_target(ads,
660 if (!ADS_ERR_OK(status)) {
665 input_name.value = p->string;
666 input_name.length = strlen(p->string);
668 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
670 ads_free_service_principal(p);
671 return ADS_ERROR_GSS(gss_rc, minor_status);
678 #endif /* HAVE_KRB5 */
681 this performs a SASL/SPNEGO bind
683 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
685 TALLOC_CTX *frame = talloc_stackframe();
686 struct ads_service_principal p = {0};
687 struct berval *scred=NULL;
691 char *given_principal = NULL;
692 char *OIDs[ASN1_MAX_OIDS];
694 bool got_kerberos_mechanism = False;
697 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
699 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
700 status = ADS_ERROR(rc);
704 blob = data_blob(scred->bv_val, scred->bv_len);
709 file_save("sasl_spnego.dat", blob.data, blob.length);
712 /* the server sent us the first part of the SPNEGO exchange in the negprot
714 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
716 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
719 TALLOC_FREE(given_principal);
721 /* make sure the server understands kerberos */
722 for (i=0;OIDs[i];i++) {
723 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
725 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
726 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
727 got_kerberos_mechanism = True;
730 talloc_free(OIDs[i]);
733 status = ads_generate_service_principal(ads, &p);
734 if (!ADS_ERR_OK(status)) {
739 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
740 got_kerberos_mechanism)
742 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
743 CRED_MUST_USE_KERBEROS,
744 p.service, p.hostname,
746 if (ADS_ERR_OK(status)) {
747 ads_free_service_principal(&p);
751 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
752 "calling kinit\n", ads_errstr(status)));
754 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
756 if (ADS_ERR_OK(status)) {
757 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
758 CRED_MUST_USE_KERBEROS,
759 p.service, p.hostname,
761 if (!ADS_ERR_OK(status)) {
762 DEBUG(0,("kinit succeeded but "
763 "ads_sasl_spnego_gensec_bind(KRB5) failed: %s\n",
764 ads_errstr(status)));
768 /* only fallback to NTLMSSP if allowed */
769 if (ADS_ERR_OK(status) ||
770 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
776 /* lets do NTLMSSP ... this has the big advantage that we don't need
777 to sync clocks, and we don't rely on special versions of the krb5
778 library for HMAC_MD4 encryption */
779 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
780 CRED_DONT_USE_KERBEROS,
781 p.service, p.hostname,
784 ads_free_service_principal(&p);
790 #define MAX_GSS_PASSES 3
792 /* this performs a SASL/gssapi bind
793 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
794 is very dependent on correctly configured DNS whereas
795 this routine is much less fragile
796 see RFC2078 and RFC2222 for details
798 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
800 uint32_t minor_status;
801 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
802 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
803 gss_OID mech_type = GSS_C_NULL_OID;
804 gss_buffer_desc output_token, input_token;
805 uint32_t req_flags, ret_flags;
808 struct berval *scred = NULL;
812 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
813 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
816 input_token.value = NULL;
817 input_token.length = 0;
819 status = ads_init_gssapi_cred(ads, &gss_cred);
820 if (!ADS_ERR_OK(status)) {
825 * Note: here we always ask the gssapi for sign and seal
826 * as this is negotiated later after the mutal
829 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
831 for (i=0; i < MAX_GSS_PASSES; i++) {
832 gss_rc = gss_init_sec_context(&minor_status,
849 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
850 status = ADS_ERROR_GSS(gss_rc, minor_status);
854 cred.bv_val = (char *)output_token.value;
855 cred.bv_len = output_token.length;
857 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
859 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
860 status = ADS_ERROR(rc);
864 if (output_token.value) {
865 gss_release_buffer(&minor_status, &output_token);
869 input_token.value = scred->bv_val;
870 input_token.length = scred->bv_len;
872 input_token.value = NULL;
873 input_token.length = 0;
876 if (gss_rc == 0) break;
879 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
886 status = ADS_ERROR_GSS(gss_rc, minor_status);
890 p = (uint8_t *)output_token.value;
893 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
897 wrap_type = CVAL(p,0);
899 max_msg_size = RIVAL(p,0);
902 gss_release_buffer(&minor_status, &output_token);
904 if (!(wrap_type & ads->ldap.wrap_type)) {
906 * the server doesn't supports the wrap
909 DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
910 ads->ldap.wrap_type, wrap_type));
911 DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
912 status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
916 /* 0x58 is the minimum windows accepts */
917 if (max_msg_size < 0x58) {
921 output_token.length = 4;
922 output_token.value = SMB_MALLOC(output_token.length);
923 if (!output_token.value) {
924 output_token.length = 0;
925 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
928 p = (uint8_t *)output_token.value;
930 RSIVAL(p,0,max_msg_size);
931 SCVAL(p,0,ads->ldap.wrap_type);
934 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
935 * but using ads->config.bind_path is the wrong! It should be
936 * the DN of the user object!
938 * w2k3 gives an error when we send an incorrect DN, but sending nothing
939 * is ok and matches the information flow used in GSS-SPNEGO.
942 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
943 &output_token, /* used as *input* here. */
945 &input_token); /* Used as *output* here. */
947 status = ADS_ERROR_GSS(gss_rc, minor_status);
948 output_token.length = 0;
949 SAFE_FREE(output_token.value);
953 /* We've finished with output_token. */
954 SAFE_FREE(output_token.value);
955 output_token.length = 0;
957 cred.bv_val = (char *)input_token.value;
958 cred.bv_len = input_token.length;
960 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL,
962 gss_release_buffer(&minor_status, &input_token);
963 status = ADS_ERROR(rc);
964 if (!ADS_ERR_OK(status)) {
968 if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
969 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
970 (ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_SEAL),
972 max_msg_size, &ads->ldap.out.max_unwrapped);
974 status = ADS_ERROR_GSS(gss_rc, minor_status);
978 ads->ldap.out.sig_size = max_msg_size - ads->ldap.out.max_unwrapped;
979 ads->ldap.in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
980 ads->ldap.in.max_wrapped = max_msg_size;
981 status = ads_setup_sasl_wrapping(ads, &ads_sasl_gssapi_ops, context_handle);
982 if (!ADS_ERR_OK(status)) {
983 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
984 ads_errstr(status)));
987 /* make sure we don't free context_handle */
988 context_handle = GSS_C_NO_CONTEXT;
992 if (gss_cred != GSS_C_NO_CREDENTIAL)
993 gss_release_cred(&minor_status, &gss_cred);
994 if (context_handle != GSS_C_NO_CONTEXT)
995 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1002 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1005 struct ads_service_principal p;
1007 status = ads_generate_service_principal(ads, &p);
1008 if (!ADS_ERR_OK(status)) {
1012 status = ads_sasl_gssapi_do_bind(ads, p.name);
1013 if (ADS_ERR_OK(status)) {
1014 ads_free_service_principal(&p);
1018 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1019 "calling kinit\n", ads_errstr(status)));
1021 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1023 if (ADS_ERR_OK(status)) {
1024 status = ads_sasl_gssapi_do_bind(ads, p.name);
1027 ads_free_service_principal(&p);
1032 #endif /* HAVE_KRB5 */
1034 /* mapping between SASL mechanisms and functions */
1037 ADS_STATUS (*fn)(ADS_STRUCT *);
1038 } sasl_mechanisms[] = {
1039 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1041 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1046 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1048 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1054 /* get a list of supported SASL mechanisms */
1055 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1056 if (!ADS_ERR_OK(status)) return status;
1058 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1060 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1061 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1062 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1063 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1065 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1068 /* try our supported mechanisms in order */
1069 for (i=0;sasl_mechanisms[i].name;i++) {
1070 /* see if the server supports it */
1071 for (j=0;values && values[j];j++) {
1072 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1073 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1075 status = sasl_mechanisms[i].fn(ads);
1076 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1077 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1078 ads->ldap.wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1080 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1081 "retrying with signing enabled\n"));
1082 ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1085 ldap_value_free(values);
1092 ldap_value_free(values);
1094 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1097 #endif /* HAVE_LDAP */