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 struct ads_service_principal {
364 static void ads_free_service_principal(struct ads_service_principal *p)
366 SAFE_FREE(p->service);
367 SAFE_FREE(p->hostname);
368 SAFE_FREE(p->string);
372 uint32_t minor_status;
373 gss_release_name(&minor_status, &p->name);
379 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
384 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
391 frame = talloc_stackframe();
393 return ADS_ERROR(LDAP_NO_MEMORY);
396 if (ads->server.realm && ads->server.ldap_server) {
397 server = strlower_talloc(frame, ads->server.ldap_server);
398 if (server == NULL) {
402 realm = strupper_talloc(frame, ads->server.realm);
408 * If we got a name which is bigger than a NetBIOS name,
409 * but isn't a FQDN, create one.
411 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
414 dnsdomain = strlower_talloc(frame, ads->server.realm);
415 if (dnsdomain == NULL) {
419 server = talloc_asprintf(frame,
422 if (server == NULL) {
426 } else if (ads->config.realm && ads->config.ldap_server_name) {
427 server = strlower_talloc(frame, ads->config.ldap_server_name);
428 if (server == NULL) {
432 realm = strupper_talloc(frame, ads->config.realm);
438 * If we got a name which is bigger than a NetBIOS name,
439 * but isn't a FQDN, create one.
441 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
444 dnsdomain = strlower_talloc(frame, ads->server.realm);
445 if (dnsdomain == NULL) {
449 server = talloc_asprintf(frame,
452 if (server == NULL) {
458 if (server == NULL || realm == NULL) {
462 *service = SMB_STRDUP("ldap");
463 if (*service == NULL) {
464 status = ADS_ERROR(LDAP_PARAM_ERROR);
467 *hostname = SMB_STRDUP(server);
468 if (*hostname == NULL) {
470 status = ADS_ERROR(LDAP_PARAM_ERROR);
473 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
474 if (rc == -1 || princ == NULL) {
476 SAFE_FREE(*hostname);
477 status = ADS_ERROR(LDAP_PARAM_ERROR);
483 status = ADS_SUCCESS;
489 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
490 struct ads_service_principal *p)
494 gss_buffer_desc input_name;
495 /* GSS_KRB5_NT_PRINCIPAL_NAME */
496 gss_OID_desc nt_principal =
497 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
498 uint32_t minor_status;
504 status = ads_guess_target(ads,
508 if (!ADS_ERR_OK(status)) {
513 input_name.value = p->string;
514 input_name.length = strlen(p->string);
516 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
518 ads_free_service_principal(p);
519 return ADS_ERROR_GSS(gss_rc, minor_status);
526 #endif /* HAVE_KRB5 */
529 this performs a SASL/SPNEGO bind
531 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
533 TALLOC_CTX *frame = talloc_stackframe();
534 struct ads_service_principal p = {0};
535 struct berval *scred=NULL;
538 DATA_BLOB blob = data_blob_null;
539 char *given_principal = NULL;
540 char *OIDs[ASN1_MAX_OIDS];
542 bool got_kerberos_mechanism = False;
544 const char *mech = NULL;
546 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
548 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
549 status = ADS_ERROR(rc);
553 blob = data_blob(scred->bv_val, scred->bv_len);
558 file_save("sasl_spnego.dat", blob.data, blob.length);
561 /* the server sent us the first part of the SPNEGO exchange in the negprot
563 if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
565 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
568 TALLOC_FREE(given_principal);
570 /* make sure the server understands kerberos */
571 for (i=0;OIDs[i];i++) {
572 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
574 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
575 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
576 got_kerberos_mechanism = True;
579 talloc_free(OIDs[i]);
582 status = ads_generate_service_principal(ads, &p);
583 if (!ADS_ERR_OK(status)) {
588 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
589 got_kerberos_mechanism)
593 if (ads->auth.password == NULL ||
594 ads->auth.password[0] == '\0')
597 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
598 CRED_MUST_USE_KERBEROS,
599 p.service, p.hostname,
601 if (ADS_ERR_OK(status)) {
602 ads_free_service_principal(&p);
606 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
607 "calling kinit\n", ads_errstr(status)));
610 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
612 if (ADS_ERR_OK(status)) {
613 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
614 CRED_MUST_USE_KERBEROS,
615 p.service, p.hostname,
617 if (!ADS_ERR_OK(status)) {
618 DEBUG(0,("kinit succeeded but "
619 "ads_sasl_spnego_gensec_bind(KRB5) failed "
620 "for %s/%s with user[%s] realm[%s]: %s\n",
621 p.service, p.hostname,
624 ads_errstr(status)));
628 /* only fallback to NTLMSSP if allowed */
629 if (ADS_ERR_OK(status) ||
630 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
634 DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
635 "for %s/%s with user[%s] realm[%s]: %s, "
636 "fallback to NTLMSSP\n",
637 p.service, p.hostname,
640 ads_errstr(status)));
644 /* lets do NTLMSSP ... this has the big advantage that we don't need
645 to sync clocks, and we don't rely on special versions of the krb5
646 library for HMAC_MD4 encryption */
648 status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
649 CRED_DONT_USE_KERBEROS,
650 p.service, p.hostname,
653 if (!ADS_ERR_OK(status)) {
654 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
655 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
656 p.service, p.hostname,
659 ads_errstr(status)));
661 ads_free_service_principal(&p);
663 if (blob.data != NULL) {
664 data_blob_free(&blob);
671 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
674 struct ads_service_principal p;
676 status = ads_generate_service_principal(ads, &p);
677 if (!ADS_ERR_OK(status)) {
681 if (ads->auth.password == NULL ||
682 ads->auth.password[0] == '\0') {
683 status = ads_sasl_spnego_gensec_bind(ads,
685 CRED_MUST_USE_KERBEROS,
689 if (ADS_ERR_OK(status)) {
690 ads_free_service_principal(&p);
694 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
695 "calling kinit\n", ads_errstr(status)));
698 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
700 if (ADS_ERR_OK(status)) {
701 status = ads_sasl_spnego_gensec_bind(ads,
703 CRED_MUST_USE_KERBEROS,
709 ads_free_service_principal(&p);
714 #endif /* HAVE_KRB5 */
716 /* mapping between SASL mechanisms and functions */
719 ADS_STATUS (*fn)(ADS_STRUCT *);
720 } sasl_mechanisms[] = {
721 {"GSS-SPNEGO", ads_sasl_spnego_bind},
723 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
728 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
730 const char *attrs[] = {"supportedSASLMechanisms", NULL};
735 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
737 /* get a list of supported SASL mechanisms */
738 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
739 if (!ADS_ERR_OK(status)) return status;
741 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
743 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
744 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
745 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
746 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
748 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
751 /* try our supported mechanisms in order */
752 for (i=0;sasl_mechanisms[i].name;i++) {
753 /* see if the server supports it */
754 for (j=0;values && values[j];j++) {
755 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
756 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
758 status = sasl_mechanisms[i].fn(ads);
759 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
760 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
761 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
763 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
764 "retrying with signing enabled\n"));
765 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
768 ldap_value_free(values);
775 ldap_value_free(values);
777 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
780 #endif /* HAVE_LDAP */