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(struct ads_saslwrap *wrap,
34 uint8_t *buf, uint32_t len)
36 struct gensec_security *gensec_security =
37 talloc_get_type_abort(wrap->wrap_private_data,
38 struct gensec_security);
40 DATA_BLOB unwrapped, wrapped;
41 TALLOC_CTX *frame = talloc_stackframe();
43 unwrapped = data_blob_const(buf, len);
45 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
46 if (!NT_STATUS_IS_OK(nt_status)) {
48 return ADS_ERROR_NT(nt_status);
51 if ((wrap->out.size - 4) < wrapped.length) {
53 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
56 /* copy the wrapped blob to the right location */
57 memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
59 /* set how many bytes must be written to the underlying socket */
60 wrap->out.left = 4 + wrapped.length;
67 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
69 struct gensec_security *gensec_security =
70 talloc_get_type_abort(wrap->wrap_private_data,
71 struct gensec_security);
73 DATA_BLOB unwrapped, wrapped;
74 TALLOC_CTX *frame = talloc_stackframe();
76 wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
78 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
79 if (!NT_STATUS_IS_OK(nt_status)) {
81 return ADS_ERROR_NT(nt_status);
84 if (wrapped.length < unwrapped.length) {
86 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
89 /* copy the wrapped blob to the right location */
90 memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
92 /* set how many bytes must be written to the underlying socket */
93 wrap->in.left = unwrapped.length;
101 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
103 struct gensec_security *gensec_security =
104 talloc_get_type_abort(wrap->wrap_private_data,
105 struct gensec_security);
107 TALLOC_FREE(gensec_security);
109 wrap->wrap_ops = NULL;
110 wrap->wrap_private_data = NULL;
113 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
115 .wrap = ads_sasl_gensec_wrap,
116 .unwrap = ads_sasl_gensec_unwrap,
117 .disconnect = ads_sasl_gensec_disconnect
121 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
122 we fit on one socket??)
124 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
126 enum credentials_use_kerberos krb5_state,
127 const char *target_service,
128 const char *target_hostname,
129 const DATA_BLOB server_blob)
131 DATA_BLOB blob_in = data_blob_null;
132 DATA_BLOB blob_out = data_blob_null;
136 struct auth_generic_state *auth_generic_state;
137 bool use_spnego_principal = lp_client_use_spnego_principal();
138 const char *sasl_list[] = { sasl, NULL };
140 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
142 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
143 if (!NT_STATUS_IS_OK(nt_status)) {
144 return ADS_ERROR_NT(nt_status);
147 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
148 return ADS_ERROR_NT(nt_status);
150 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
151 return ADS_ERROR_NT(nt_status);
153 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
154 return ADS_ERROR_NT(nt_status);
157 if (server_blob.length == 0) {
158 use_spnego_principal = false;
161 if (krb5_state == CRED_DONT_USE_KERBEROS) {
162 use_spnego_principal = false;
165 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
168 if (target_service != NULL) {
169 nt_status = gensec_set_target_service(
170 auth_generic_state->gensec_security,
172 if (!NT_STATUS_IS_OK(nt_status)) {
173 return ADS_ERROR_NT(nt_status);
177 if (target_hostname != NULL) {
178 nt_status = gensec_set_target_hostname(
179 auth_generic_state->gensec_security,
181 if (!NT_STATUS_IS_OK(nt_status)) {
182 return ADS_ERROR_NT(nt_status);
186 if (target_service != NULL && target_hostname != NULL) {
187 use_spnego_principal = false;
190 switch (wrap->wrap_type) {
191 case ADS_SASLWRAP_TYPE_SEAL:
192 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
193 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
195 case ADS_SASLWRAP_TYPE_SIGN:
196 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
197 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
200 * windows servers are broken with sign only,
201 * so we let the NTLMSSP backend to seal here,
202 * via GENSEC_FEATURE_LDAP_STYLE.
204 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
205 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
208 case ADS_SASLWRAP_TYPE_PLAIN:
212 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
214 if (!NT_STATUS_IS_OK(nt_status)) {
215 return ADS_ERROR_NT(nt_status);
218 rc = LDAP_SASL_BIND_IN_PROGRESS;
219 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
220 if (use_spnego_principal) {
221 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
222 if (blob_in.length == 0) {
223 TALLOC_FREE(auth_generic_state);
224 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
227 blob_in = data_blob_null;
229 blob_out = data_blob_null;
232 struct berval cred, *scred = NULL;
234 nt_status = gensec_update(auth_generic_state->gensec_security,
235 talloc_tos(), blob_in, &blob_out);
236 data_blob_free(&blob_in);
237 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
238 && !NT_STATUS_IS_OK(nt_status))
240 TALLOC_FREE(auth_generic_state);
241 data_blob_free(&blob_out);
242 return ADS_ERROR_NT(nt_status);
245 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
249 cred.bv_val = (char *)blob_out.data;
250 cred.bv_len = blob_out.length;
252 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
253 data_blob_free(&blob_out);
254 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
259 TALLOC_FREE(auth_generic_state);
260 return ADS_ERROR(rc);
263 blob_in = data_blob_talloc(talloc_tos(),
266 if (blob_in.length != scred->bv_len) {
268 TALLOC_FREE(auth_generic_state);
269 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
273 blob_in = data_blob_null;
275 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
280 data_blob_free(&blob_in);
281 data_blob_free(&blob_out);
283 if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
286 ok = gensec_have_feature(auth_generic_state->gensec_security,
287 GENSEC_FEATURE_SEAL);
289 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
290 TALLOC_FREE(auth_generic_state);
291 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
294 ok = gensec_have_feature(auth_generic_state->gensec_security,
295 GENSEC_FEATURE_SIGN);
297 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
298 TALLOC_FREE(auth_generic_state);
299 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
302 } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
305 ok = gensec_have_feature(auth_generic_state->gensec_security,
306 GENSEC_FEATURE_SIGN);
308 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
309 TALLOC_FREE(auth_generic_state);
310 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
314 ads->auth.tgs_expire = LONG_MAX;
315 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
316 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
318 nttime_to_timeval(&tv, end_nt_time);
319 ads->auth.tgs_expire = tv.tv_sec;
322 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
324 gensec_max_wrapped_size(auth_generic_state->gensec_security);
325 wrap->out.max_unwrapped =
326 gensec_max_input_size(auth_generic_state->gensec_security);
328 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
330 * Note that we have to truncate this to 0x2C
331 * (taken from a capture with LDAP unbind), as the
332 * signature size is not constant for Kerberos with
335 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
336 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
337 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
338 &ads_sasl_gensec_ops,
339 auth_generic_state->gensec_security);
340 if (!ADS_ERR_OK(status)) {
341 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
342 ads_errstr(status)));
343 TALLOC_FREE(auth_generic_state);
346 /* Only keep the gensec_security element around long-term */
347 talloc_steal(NULL, auth_generic_state->gensec_security);
349 TALLOC_FREE(auth_generic_state);
351 return ADS_ERROR(rc);
355 static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
359 krb5_error_code kerr;
360 krb5_ccache kccache = NULL;
363 *cred = GSS_C_NO_CREDENTIAL;
365 if (!ads->auth.ccache_name) {
369 kerr = smb_krb5_init_context_common(&kctx);
371 DBG_ERR("kerberos init context failed (%s)\n",
372 error_message(kerr));
373 return ADS_ERROR_KRB5(kerr);
376 kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
378 status = ADS_ERROR_KRB5(kerr);
382 maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
383 if (maj != GSS_S_COMPLETE) {
384 status = ADS_ERROR_GSS(maj, min);
388 status = ADS_SUCCESS;
391 if (!ADS_ERR_OK(status) && kccache != NULL) {
392 krb5_cc_close(kctx, kccache);
394 krb5_free_context(kctx);
398 static ADS_STATUS ads_sasl_gssapi_wrap(struct ads_saslwrap *wrap, uint8_t *buf, uint32_t len)
400 gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
403 uint32_t minor_status;
404 gss_buffer_desc unwrapped, wrapped;
405 int conf_req_flag, conf_state;
407 unwrapped.value = buf;
408 unwrapped.length = len;
410 /* for now request sign and seal */
411 conf_req_flag = (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL);
413 gss_rc = gss_wrap(&minor_status, context_handle,
414 conf_req_flag, GSS_C_QOP_DEFAULT,
415 &unwrapped, &conf_state,
417 status = ADS_ERROR_GSS(gss_rc, minor_status);
418 if (!ADS_ERR_OK(status)) return status;
420 if (conf_req_flag && conf_state == 0) {
421 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
424 if ((wrap->out.size - 4) < wrapped.length) {
425 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
428 /* copy the wrapped blob to the right location */
429 memcpy(wrap->out.buf + 4, wrapped.value, wrapped.length);
431 /* set how many bytes must be written to the underlying socket */
432 wrap->out.left = 4 + wrapped.length;
434 gss_release_buffer(&minor_status, &wrapped);
439 static ADS_STATUS ads_sasl_gssapi_unwrap(struct ads_saslwrap *wrap)
441 gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
444 uint32_t minor_status;
445 gss_buffer_desc unwrapped, wrapped;
448 wrapped.value = wrap->in.buf + 4;
449 wrapped.length = wrap->in.ofs - 4;
451 gss_rc = gss_unwrap(&minor_status, context_handle,
452 &wrapped, &unwrapped,
453 &conf_state, GSS_C_QOP_DEFAULT);
454 status = ADS_ERROR_GSS(gss_rc, minor_status);
455 if (!ADS_ERR_OK(status)) return status;
457 if (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL && conf_state == 0) {
458 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
461 if (wrapped.length < unwrapped.length) {
462 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
465 /* copy the wrapped blob to the right location */
466 memcpy(wrap->in.buf + 4, unwrapped.value, unwrapped.length);
468 /* set how many bytes must be written to the underlying socket */
469 wrap->in.left = unwrapped.length;
472 gss_release_buffer(&minor_status, &unwrapped);
477 static void ads_sasl_gssapi_disconnect(struct ads_saslwrap *wrap)
479 gss_ctx_id_t context_handle = (gss_ctx_id_t)wrap->wrap_private_data;
480 uint32_t minor_status;
482 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
484 wrap->wrap_ops = NULL;
485 wrap->wrap_private_data = NULL;
488 static const struct ads_saslwrap_ops ads_sasl_gssapi_ops = {
490 .wrap = ads_sasl_gssapi_wrap,
491 .unwrap = ads_sasl_gssapi_unwrap,
492 .disconnect = ads_sasl_gssapi_disconnect
495 #endif /* HAVE_KRB5 */
498 struct ads_service_principal {
507 static void ads_free_service_principal(struct ads_service_principal *p)
509 SAFE_FREE(p->service);
510 SAFE_FREE(p->hostname);
511 SAFE_FREE(p->string);
515 uint32_t minor_status;
516 gss_release_name(&minor_status, &p->name);
522 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
527 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
534 frame = talloc_stackframe();
536 return ADS_ERROR(LDAP_NO_MEMORY);
539 if (ads->server.realm && ads->server.ldap_server) {
540 server = strlower_talloc(frame, ads->server.ldap_server);
541 if (server == NULL) {
545 realm = strupper_talloc(frame, ads->server.realm);
551 * If we got a name which is bigger than a NetBIOS name,
552 * but isn't a FQDN, create one.
554 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
557 dnsdomain = strlower_talloc(frame, ads->server.realm);
558 if (dnsdomain == NULL) {
562 server = talloc_asprintf(frame,
565 if (server == NULL) {
569 } else if (ads->config.realm && ads->config.ldap_server_name) {
570 server = strlower_talloc(frame, ads->config.ldap_server_name);
571 if (server == NULL) {
575 realm = strupper_talloc(frame, ads->config.realm);
581 * If we got a name which is bigger than a NetBIOS name,
582 * but isn't a FQDN, create one.
584 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
587 dnsdomain = strlower_talloc(frame, ads->server.realm);
588 if (dnsdomain == NULL) {
592 server = talloc_asprintf(frame,
595 if (server == NULL) {
601 if (server == NULL || realm == NULL) {
605 *service = SMB_STRDUP("ldap");
606 if (*service == NULL) {
607 status = ADS_ERROR(LDAP_PARAM_ERROR);
610 *hostname = SMB_STRDUP(server);
611 if (*hostname == NULL) {
613 status = ADS_ERROR(LDAP_PARAM_ERROR);
616 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
617 if (rc == -1 || princ == NULL) {
619 SAFE_FREE(*hostname);
620 status = ADS_ERROR(LDAP_PARAM_ERROR);
626 status = ADS_SUCCESS;
632 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
633 struct ads_service_principal *p)
637 gss_buffer_desc input_name;
638 /* GSS_KRB5_NT_PRINCIPAL_NAME */
639 gss_OID_desc nt_principal =
640 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
641 uint32_t minor_status;
647 status = ads_guess_target(ads,
651 if (!ADS_ERR_OK(status)) {
656 input_name.value = p->string;
657 input_name.length = strlen(p->string);
659 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
661 ads_free_service_principal(p);
662 return ADS_ERROR_GSS(gss_rc, minor_status);
669 #endif /* HAVE_KRB5 */
672 this performs a SASL/SPNEGO bind
674 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
676 TALLOC_CTX *frame = talloc_stackframe();
677 struct ads_service_principal p = {0};
678 struct berval *scred=NULL;
681 DATA_BLOB blob = data_blob_null;
682 char *given_principal = NULL;
683 char *OIDs[ASN1_MAX_OIDS];
685 bool got_kerberos_mechanism = False;
687 const char *mech = NULL;
689 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
691 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
692 status = ADS_ERROR(rc);
696 blob = data_blob(scred->bv_val, scred->bv_len);
701 file_save("sasl_spnego.dat", blob.data, blob.length);
704 /* the server sent us the first part of the SPNEGO exchange in the negprot
706 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
708 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
711 TALLOC_FREE(given_principal);
713 /* make sure the server understands kerberos */
714 for (i=0;OIDs[i];i++) {
715 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
717 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
718 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
719 got_kerberos_mechanism = True;
722 talloc_free(OIDs[i]);
725 status = ads_generate_service_principal(ads, &p);
726 if (!ADS_ERR_OK(status)) {
731 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
732 got_kerberos_mechanism)
736 if (ads->auth.password == NULL ||
737 ads->auth.password[0] == '\0')
740 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
741 CRED_MUST_USE_KERBEROS,
742 p.service, p.hostname,
744 if (ADS_ERR_OK(status)) {
745 ads_free_service_principal(&p);
749 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
750 "calling kinit\n", ads_errstr(status)));
753 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
755 if (ADS_ERR_OK(status)) {
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 DEBUG(0,("kinit succeeded but "
762 "ads_sasl_spnego_gensec_bind(KRB5) failed "
763 "for %s/%s with user[%s] realm[%s]: %s\n",
764 p.service, p.hostname,
767 ads_errstr(status)));
771 /* only fallback to NTLMSSP if allowed */
772 if (ADS_ERR_OK(status) ||
773 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
777 DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
778 "for %s/%s with user[%s] realm[%s]: %s, "
779 "fallback to NTLMSSP\n",
780 p.service, p.hostname,
783 ads_errstr(status)));
787 /* lets do NTLMSSP ... this has the big advantage that we don't need
788 to sync clocks, and we don't rely on special versions of the krb5
789 library for HMAC_MD4 encryption */
791 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
792 CRED_DONT_USE_KERBEROS,
793 p.service, p.hostname,
796 if (!ADS_ERR_OK(status)) {
797 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
798 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
799 p.service, p.hostname,
802 ads_errstr(status)));
804 ads_free_service_principal(&p);
806 if (blob.data != NULL) {
807 data_blob_free(&blob);
813 #define MAX_GSS_PASSES 3
815 /* this performs a SASL/gssapi bind
816 we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
817 is very dependent on correctly configured DNS whereas
818 this routine is much less fragile
819 see RFC2078 and RFC2222 for details
821 static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
823 uint32_t minor_status;
824 gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
825 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
826 gss_OID mech_type = GSS_C_NULL_OID;
827 gss_buffer_desc output_token, input_token;
828 uint32_t req_flags, ret_flags;
831 struct berval *scred = NULL;
835 uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
836 uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
838 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
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 & wrap->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 wrap->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,wrap->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 (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
993 gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
994 (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL),
996 max_msg_size, &wrap->out.max_unwrapped);
998 status = ADS_ERROR_GSS(gss_rc, minor_status);
1002 wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped;
1003 wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
1004 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
1005 status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld,
1006 &ads_sasl_gssapi_ops,
1008 if (!ADS_ERR_OK(status)) {
1009 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
1010 ads_errstr(status)));
1013 /* make sure we don't free context_handle */
1014 context_handle = GSS_C_NO_CONTEXT;
1018 if (gss_cred != GSS_C_NO_CREDENTIAL)
1019 gss_release_cred(&minor_status, &gss_cred);
1020 if (context_handle != GSS_C_NO_CONTEXT)
1021 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
1028 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
1031 struct ads_service_principal p;
1033 status = ads_generate_service_principal(ads, &p);
1034 if (!ADS_ERR_OK(status)) {
1038 if (ads->auth.password == NULL ||
1039 ads->auth.password[0] == '\0') {
1040 status = ads_sasl_gssapi_do_bind(ads, p.name);
1041 if (ADS_ERR_OK(status)) {
1042 ads_free_service_principal(&p);
1046 DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, "
1047 "calling kinit\n", ads_errstr(status)));
1050 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
1052 if (ADS_ERR_OK(status)) {
1053 status = ads_sasl_gssapi_do_bind(ads, p.name);
1056 ads_free_service_principal(&p);
1061 #endif /* HAVE_KRB5 */
1063 /* mapping between SASL mechanisms and functions */
1066 ADS_STATUS (*fn)(ADS_STRUCT *);
1067 } sasl_mechanisms[] = {
1068 {"GSS-SPNEGO", ads_sasl_spnego_bind},
1070 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
1075 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
1077 const char *attrs[] = {"supportedSASLMechanisms", NULL};
1082 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
1084 /* get a list of supported SASL mechanisms */
1085 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
1086 if (!ADS_ERR_OK(status)) return status;
1088 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
1090 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
1091 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
1092 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
1093 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1095 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
1098 /* try our supported mechanisms in order */
1099 for (i=0;sasl_mechanisms[i].name;i++) {
1100 /* see if the server supports it */
1101 for (j=0;values && values[j];j++) {
1102 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
1103 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
1105 status = sasl_mechanisms[i].fn(ads);
1106 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
1107 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
1108 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
1110 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
1111 "retrying with signing enabled\n"));
1112 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
1115 ldap_value_free(values);
1122 ldap_value_free(values);
1124 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
1127 #endif /* HAVE_LDAP */