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 "auth/credentials/credentials.h"
22 #include "auth/gensec/gensec.h"
23 #include "auth_generic.h"
26 #include "system/gssapi.h"
27 #include "lib/param/loadparm.h"
29 #include "lib/util/asn1.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,
125 enum credentials_use_kerberos krb5_state,
126 const char *target_service,
127 const char *target_hostname)
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 const char *sasl = "GSS-SPNEGO";
136 const char *sasl_list[] = { sasl, NULL };
138 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
139 const DATA_BLOB *tls_cb = NULL;
141 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
142 if (!NT_STATUS_IS_OK(nt_status)) {
143 return ADS_ERROR_NT(nt_status);
146 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
147 return ADS_ERROR_NT(nt_status);
149 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
150 return ADS_ERROR_NT(nt_status);
152 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
153 return ADS_ERROR_NT(nt_status);
156 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
160 if (target_service != NULL) {
161 nt_status = gensec_set_target_service(
162 auth_generic_state->gensec_security,
164 if (!NT_STATUS_IS_OK(nt_status)) {
165 return ADS_ERROR_NT(nt_status);
169 if (target_hostname != NULL) {
170 nt_status = gensec_set_target_hostname(
171 auth_generic_state->gensec_security,
173 if (!NT_STATUS_IS_OK(nt_status)) {
174 return ADS_ERROR_NT(nt_status);
178 tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
179 if (tls_cb != NULL) {
180 uint32_t initiator_addrtype = 0;
181 const DATA_BLOB *initiator_address = NULL;
182 uint32_t acceptor_addrtype = 0;
183 const DATA_BLOB *acceptor_address = NULL;
184 const DATA_BLOB *application_data = tls_cb;
186 nt_status = gensec_set_channel_bindings(auth_generic_state->gensec_security,
192 if (!NT_STATUS_IS_OK(nt_status)) {
193 DBG_WARNING("Failed to set GENSEC channel bindings: %s\n",
194 nt_errstr(nt_status));
195 return ADS_ERROR_NT(nt_status);
199 switch (wrap->wrap_type) {
200 case ADS_SASLWRAP_TYPE_SEAL:
201 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
202 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
204 case ADS_SASLWRAP_TYPE_SIGN:
205 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
206 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
209 * windows servers are broken with sign only,
210 * so we let the NTLMSSP backend to seal here,
211 * via GENSEC_FEATURE_LDAP_STYLE.
213 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
214 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
217 case ADS_SASLWRAP_TYPE_PLAIN:
221 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
223 if (!NT_STATUS_IS_OK(nt_status)) {
224 return ADS_ERROR_NT(nt_status);
227 rc = LDAP_SASL_BIND_IN_PROGRESS;
228 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 {
361 static void ads_free_service_principal(struct ads_service_principal *p)
363 SAFE_FREE(p->service);
364 SAFE_FREE(p->hostname);
365 SAFE_FREE(p->string);
369 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
374 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
381 frame = talloc_stackframe();
383 return ADS_ERROR(LDAP_NO_MEMORY);
386 if (ads->server.realm && ads->server.ldap_server) {
387 server = strlower_talloc(frame, ads->server.ldap_server);
388 if (server == NULL) {
392 realm = strupper_talloc(frame, ads->server.realm);
398 * If we got a name which is bigger than a NetBIOS name,
399 * but isn't a FQDN, create one.
401 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
404 dnsdomain = strlower_talloc(frame, ads->server.realm);
405 if (dnsdomain == NULL) {
409 server = talloc_asprintf(frame,
412 if (server == NULL) {
416 } else if (ads->config.realm && ads->config.ldap_server_name) {
417 server = strlower_talloc(frame, ads->config.ldap_server_name);
418 if (server == NULL) {
422 realm = strupper_talloc(frame, ads->config.realm);
428 * If we got a name which is bigger than a NetBIOS name,
429 * but isn't a FQDN, create one.
431 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
434 dnsdomain = strlower_talloc(frame, ads->server.realm);
435 if (dnsdomain == NULL) {
439 server = talloc_asprintf(frame,
442 if (server == NULL) {
448 if (server == NULL || realm == NULL) {
452 *service = SMB_STRDUP("ldap");
453 if (*service == NULL) {
454 status = ADS_ERROR(LDAP_PARAM_ERROR);
457 *hostname = SMB_STRDUP(server);
458 if (*hostname == NULL) {
460 status = ADS_ERROR(LDAP_PARAM_ERROR);
463 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
464 if (rc == -1 || princ == NULL) {
466 SAFE_FREE(*hostname);
467 status = ADS_ERROR(LDAP_PARAM_ERROR);
473 status = ADS_SUCCESS;
479 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
480 struct ads_service_principal *p)
486 status = ads_guess_target(ads,
490 if (!ADS_ERR_OK(status)) {
497 #endif /* HAVE_KRB5 */
500 this performs a SASL/SPNEGO bind
502 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
504 TALLOC_CTX *frame = talloc_stackframe();
505 struct ads_service_principal p = {0};
507 const char *mech = NULL;
509 status = ads_generate_service_principal(ads, &p);
510 if (!ADS_ERR_OK(status)) {
515 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
516 !is_ipaddress(p.hostname))
520 if (ads->auth.password == NULL ||
521 ads->auth.password[0] == '\0')
524 status = ads_sasl_spnego_gensec_bind(ads,
525 CRED_USE_KERBEROS_REQUIRED,
526 p.service, p.hostname);
527 if (ADS_ERR_OK(status)) {
528 ads_free_service_principal(&p);
532 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
533 "calling kinit\n", ads_errstr(status)));
536 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
538 if (ADS_ERR_OK(status)) {
539 status = ads_sasl_spnego_gensec_bind(ads,
540 CRED_USE_KERBEROS_REQUIRED,
541 p.service, p.hostname);
542 if (!ADS_ERR_OK(status)) {
543 DBG_ERR("kinit succeeded but "
544 "SPNEGO bind with Kerberos failed "
545 "for %s/%s - user[%s], realm[%s]: %s\n",
546 p.service, p.hostname,
553 /* only fallback to NTLMSSP if allowed */
554 if (ADS_ERR_OK(status) ||
555 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
559 DBG_WARNING("SASL bind with Kerberos failed "
560 "for %s/%s - user[%s], realm[%s]: %s, "
561 "try to fallback to NTLMSSP\n",
562 p.service, p.hostname,
569 /* lets do NTLMSSP ... this has the big advantage that we don't need
570 to sync clocks, and we don't rely on special versions of the krb5
571 library for HMAC_MD4 encryption */
574 if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
575 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
576 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
580 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
581 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
583 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
587 status = ads_sasl_spnego_gensec_bind(ads,
588 CRED_USE_KERBEROS_DISABLED,
589 p.service, p.hostname);
591 if (!ADS_ERR_OK(status)) {
592 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
593 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
594 p.service, p.hostname,
597 ads_errstr(status)));
599 ads_free_service_principal(&p);
604 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
607 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
610 if (ads->auth.flags & ADS_AUTH_SASL_LDAPS) {
612 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
613 } else if (ads->auth.flags & ADS_AUTH_SASL_STARTTLS) {
615 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
616 } else if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
617 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
618 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
619 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
621 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
625 const DATA_BLOB *tls_cb = NULL;
627 tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
628 if (tls_cb == NULL) {
629 DBG_ERR("No TLS channel bindings available\n");
630 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
635 status = ads_sasl_spnego_bind(ads);
636 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
637 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
639 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
641 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
642 "retrying with signing enabled\n"));
643 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
649 #endif /* HAVE_LDAP */