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"
32 static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
33 uint8_t *buf, uint32_t len)
35 struct gensec_security *gensec_security =
36 talloc_get_type_abort(wrap->wrap_private_data,
37 struct gensec_security);
39 DATA_BLOB unwrapped, wrapped;
40 TALLOC_CTX *frame = talloc_stackframe();
42 unwrapped = data_blob_const(buf, len);
44 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
45 if (!NT_STATUS_IS_OK(nt_status)) {
47 return ADS_ERROR_NT(nt_status);
50 if ((wrap->out.size - 4) < wrapped.length) {
52 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
55 /* copy the wrapped blob to the right location */
56 memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
58 /* set how many bytes must be written to the underlying socket */
59 wrap->out.left = 4 + wrapped.length;
66 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
68 struct gensec_security *gensec_security =
69 talloc_get_type_abort(wrap->wrap_private_data,
70 struct gensec_security);
72 DATA_BLOB unwrapped, wrapped;
73 TALLOC_CTX *frame = talloc_stackframe();
75 wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
77 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
78 if (!NT_STATUS_IS_OK(nt_status)) {
80 return ADS_ERROR_NT(nt_status);
83 if (wrapped.length < unwrapped.length) {
85 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
88 /* copy the wrapped blob to the right location */
89 memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
91 /* set how many bytes must be written to the underlying socket */
92 wrap->in.left = unwrapped.length;
100 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
102 struct gensec_security *gensec_security =
103 talloc_get_type_abort(wrap->wrap_private_data,
104 struct gensec_security);
106 TALLOC_FREE(gensec_security);
108 wrap->wrap_ops = NULL;
109 wrap->wrap_private_data = NULL;
112 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
114 .wrap = ads_sasl_gensec_wrap,
115 .unwrap = ads_sasl_gensec_unwrap,
116 .disconnect = ads_sasl_gensec_disconnect
120 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
121 we fit on one socket??)
123 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)
128 DATA_BLOB blob_in = data_blob_null;
129 DATA_BLOB blob_out = data_blob_null;
133 struct auth_generic_state *auth_generic_state;
134 const char *sasl = "GSS-SPNEGO";
135 const char *sasl_list[] = { sasl, NULL };
137 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
138 const DATA_BLOB *tls_cb = NULL;
140 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
141 if (!NT_STATUS_IS_OK(nt_status)) {
142 return ADS_ERROR_NT(nt_status);
145 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) {
146 return ADS_ERROR_NT(nt_status);
148 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) {
149 return ADS_ERROR_NT(nt_status);
151 if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) {
152 return ADS_ERROR_NT(nt_status);
155 cli_credentials_set_kerberos_state(auth_generic_state->credentials,
159 if (target_service != NULL) {
160 nt_status = gensec_set_target_service(
161 auth_generic_state->gensec_security,
163 if (!NT_STATUS_IS_OK(nt_status)) {
164 return ADS_ERROR_NT(nt_status);
168 if (target_hostname != NULL) {
169 nt_status = gensec_set_target_hostname(
170 auth_generic_state->gensec_security,
172 if (!NT_STATUS_IS_OK(nt_status)) {
173 return ADS_ERROR_NT(nt_status);
177 tls_cb = ads_tls_channel_bindings(&ads->ldap_tls_data);
178 if (tls_cb != NULL) {
179 uint32_t initiator_addrtype = 0;
180 const DATA_BLOB *initiator_address = NULL;
181 uint32_t acceptor_addrtype = 0;
182 const DATA_BLOB *acceptor_address = NULL;
183 const DATA_BLOB *application_data = tls_cb;
185 nt_status = gensec_set_channel_bindings(auth_generic_state->gensec_security,
191 if (!NT_STATUS_IS_OK(nt_status)) {
192 DBG_WARNING("Failed to set GENSEC channel bindings: %s\n",
193 nt_errstr(nt_status));
194 return ADS_ERROR_NT(nt_status);
197 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
200 switch (wrap->wrap_type) {
201 case ADS_SASLWRAP_TYPE_SEAL:
202 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
203 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
205 case ADS_SASLWRAP_TYPE_SIGN:
206 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
207 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
210 * windows servers are broken with sign only,
211 * so we let the NTLMSSP backend to seal here,
212 * via GENSEC_FEATURE_LDAP_STYLE.
214 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
215 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
218 case ADS_SASLWRAP_TYPE_PLAIN:
222 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
224 if (!NT_STATUS_IS_OK(nt_status)) {
225 return ADS_ERROR_NT(nt_status);
228 rc = LDAP_SASL_BIND_IN_PROGRESS;
229 blob_in = data_blob_null;
230 blob_out = data_blob_null;
233 struct berval cred, *scred = NULL;
235 nt_status = gensec_update(auth_generic_state->gensec_security,
236 talloc_tos(), blob_in, &blob_out);
237 data_blob_free(&blob_in);
238 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
239 && !NT_STATUS_IS_OK(nt_status))
241 TALLOC_FREE(auth_generic_state);
242 data_blob_free(&blob_out);
243 return ADS_ERROR_NT(nt_status);
246 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
250 cred.bv_val = (char *)blob_out.data;
251 cred.bv_len = blob_out.length;
253 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
254 data_blob_free(&blob_out);
255 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
260 TALLOC_FREE(auth_generic_state);
261 return ADS_ERROR(rc);
264 blob_in = data_blob_talloc(talloc_tos(),
267 if (blob_in.length != scred->bv_len) {
269 TALLOC_FREE(auth_generic_state);
270 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
274 blob_in = data_blob_null;
276 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
281 data_blob_free(&blob_in);
282 data_blob_free(&blob_out);
284 if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
287 ok = gensec_have_feature(auth_generic_state->gensec_security,
288 GENSEC_FEATURE_SEAL);
290 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
291 TALLOC_FREE(auth_generic_state);
292 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
295 ok = gensec_have_feature(auth_generic_state->gensec_security,
296 GENSEC_FEATURE_SIGN);
298 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
299 TALLOC_FREE(auth_generic_state);
300 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
303 } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
306 ok = gensec_have_feature(auth_generic_state->gensec_security,
307 GENSEC_FEATURE_SIGN);
309 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
310 TALLOC_FREE(auth_generic_state);
311 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
315 ads->auth.tgs_expire = LONG_MAX;
316 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
317 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
319 nttime_to_timeval(&tv, end_nt_time);
320 ads->auth.tgs_expire = tv.tv_sec;
323 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
325 gensec_max_wrapped_size(auth_generic_state->gensec_security);
326 wrap->out.max_unwrapped =
327 gensec_max_input_size(auth_generic_state->gensec_security);
329 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
331 * Note that we have to truncate this to 0x2C
332 * (taken from a capture with LDAP unbind), as the
333 * signature size is not constant for Kerberos with
336 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
337 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
338 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
339 &ads_sasl_gensec_ops,
340 auth_generic_state->gensec_security);
341 if (!ADS_ERR_OK(status)) {
342 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
343 ads_errstr(status)));
344 TALLOC_FREE(auth_generic_state);
347 /* Only keep the gensec_security element around long-term */
348 talloc_steal(NULL, auth_generic_state->gensec_security);
350 TALLOC_FREE(auth_generic_state);
352 return ADS_ERROR(rc);
356 struct ads_service_principal {
362 static void ads_free_service_principal(struct ads_service_principal *p)
364 SAFE_FREE(p->service);
365 SAFE_FREE(p->hostname);
366 SAFE_FREE(p->string);
370 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
375 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
382 frame = talloc_stackframe();
384 return ADS_ERROR(LDAP_NO_MEMORY);
387 if (ads->server.realm && ads->server.ldap_server) {
388 server = strlower_talloc(frame, ads->server.ldap_server);
389 if (server == NULL) {
393 realm = strupper_talloc(frame, ads->server.realm);
399 * If we got a name which is bigger than a NetBIOS name,
400 * but isn't a FQDN, create one.
402 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
405 dnsdomain = strlower_talloc(frame, ads->server.realm);
406 if (dnsdomain == NULL) {
410 server = talloc_asprintf(frame,
413 if (server == NULL) {
417 } else if (ads->config.realm && ads->config.ldap_server_name) {
418 server = strlower_talloc(frame, ads->config.ldap_server_name);
419 if (server == NULL) {
423 realm = strupper_talloc(frame, ads->config.realm);
429 * If we got a name which is bigger than a NetBIOS name,
430 * but isn't a FQDN, create one.
432 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
435 dnsdomain = strlower_talloc(frame, ads->server.realm);
436 if (dnsdomain == NULL) {
440 server = talloc_asprintf(frame,
443 if (server == NULL) {
449 if (server == NULL || realm == NULL) {
453 *service = SMB_STRDUP("ldap");
454 if (*service == NULL) {
455 status = ADS_ERROR(LDAP_PARAM_ERROR);
458 *hostname = SMB_STRDUP(server);
459 if (*hostname == NULL) {
461 status = ADS_ERROR(LDAP_PARAM_ERROR);
464 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
465 if (rc == -1 || princ == NULL) {
467 SAFE_FREE(*hostname);
468 status = ADS_ERROR(LDAP_PARAM_ERROR);
474 status = ADS_SUCCESS;
480 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
481 struct ads_service_principal *p)
487 status = ads_guess_target(ads,
491 if (!ADS_ERR_OK(status)) {
498 #endif /* HAVE_KRB5 */
501 this performs a SASL/SPNEGO bind
503 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
505 TALLOC_CTX *frame = talloc_stackframe();
506 struct ads_service_principal p = {0};
508 const char *mech = NULL;
510 status = ads_generate_service_principal(ads, &p);
511 if (!ADS_ERR_OK(status)) {
516 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
517 !is_ipaddress(p.hostname))
521 if (ads->auth.password == NULL ||
522 ads->auth.password[0] == '\0')
525 status = ads_sasl_spnego_gensec_bind(ads,
526 CRED_USE_KERBEROS_REQUIRED,
527 p.service, p.hostname);
528 if (ADS_ERR_OK(status)) {
529 ads_free_service_principal(&p);
533 DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
534 "calling kinit\n", ads_errstr(status)));
537 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
539 if (ADS_ERR_OK(status)) {
540 status = ads_sasl_spnego_gensec_bind(ads,
541 CRED_USE_KERBEROS_REQUIRED,
542 p.service, p.hostname);
543 if (!ADS_ERR_OK(status)) {
544 DBG_ERR("kinit succeeded but "
545 "SPNEGO bind with Kerberos failed "
546 "for %s/%s - user[%s], realm[%s]: %s\n",
547 p.service, p.hostname,
554 /* only fallback to NTLMSSP if allowed */
555 if (ADS_ERR_OK(status) ||
556 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
560 DBG_WARNING("SASL bind with Kerberos failed "
561 "for %s/%s - user[%s], realm[%s]: %s, "
562 "try to fallback to NTLMSSP\n",
563 p.service, p.hostname,
570 /* lets do NTLMSSP ... this has the big advantage that we don't need
571 to sync clocks, and we don't rely on special versions of the krb5
572 library for HMAC_MD4 encryption */
575 if (!(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
576 DBG_WARNING("We can't use NTLMSSP, it is not allowed.\n");
577 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
581 if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
582 DBG_WARNING("We can't fallback to NTLMSSP, weak crypto is"
584 status = ADS_ERROR_NT(NT_STATUS_NETWORK_CREDENTIAL_CONFLICT);
588 status = ads_sasl_spnego_gensec_bind(ads,
589 CRED_USE_KERBEROS_DISABLED,
590 p.service, p.hostname);
592 if (!ADS_ERR_OK(status)) {
593 DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
594 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
595 p.service, p.hostname,
598 ads_errstr(status)));
600 ads_free_service_principal(&p);
605 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
608 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
610 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
611 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
612 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
613 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
615 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
619 status = ads_sasl_spnego_bind(ads);
620 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
621 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
622 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
624 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
625 "retrying with signing enabled\n"));
626 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
632 #endif /* HAVE_LDAP */