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/param.h"
31 static struct cli_credentials *ads_sasl_creds_init(TALLOC_CTX *mem_ctx,
36 enum credentials_use_kerberos krb5_state)
38 struct loadparm_context *lp_ctx;
39 struct cli_credentials *creds;
42 creds = cli_credentials_init(mem_ctx);
47 lp_ctx = loadparm_init_s3(creds, loadparm_s3_helpers());
51 cli_credentials_set_conf(creds, lp_ctx);
53 if (username != NULL) {
54 ok = cli_credentials_set_username(creds,
62 if (password != NULL) {
63 ok = cli_credentials_set_password(creds,
72 ok = cli_credentials_set_domain(creds,
81 ok = cli_credentials_set_realm(creds,
89 cli_credentials_set_kerberos_state(creds, krb5_state);
99 static ADS_STATUS ads_sasl_gensec_wrap(struct ads_saslwrap *wrap,
100 uint8_t *buf, uint32_t len)
102 struct gensec_security *gensec_security =
103 talloc_get_type_abort(wrap->wrap_private_data,
104 struct gensec_security);
106 DATA_BLOB unwrapped, wrapped;
107 TALLOC_CTX *frame = talloc_stackframe();
109 unwrapped = data_blob_const(buf, len);
111 nt_status = gensec_wrap(gensec_security, frame, &unwrapped, &wrapped);
112 if (!NT_STATUS_IS_OK(nt_status)) {
114 return ADS_ERROR_NT(nt_status);
117 if ((wrap->out.size - 4) < wrapped.length) {
119 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
122 /* copy the wrapped blob to the right location */
123 memcpy(wrap->out.buf + 4, wrapped.data, wrapped.length);
125 /* set how many bytes must be written to the underlying socket */
126 wrap->out.left = 4 + wrapped.length;
133 static ADS_STATUS ads_sasl_gensec_unwrap(struct ads_saslwrap *wrap)
135 struct gensec_security *gensec_security =
136 talloc_get_type_abort(wrap->wrap_private_data,
137 struct gensec_security);
139 DATA_BLOB unwrapped, wrapped;
140 TALLOC_CTX *frame = talloc_stackframe();
142 wrapped = data_blob_const(wrap->in.buf + 4, wrap->in.ofs - 4);
144 nt_status = gensec_unwrap(gensec_security, frame, &wrapped, &unwrapped);
145 if (!NT_STATUS_IS_OK(nt_status)) {
147 return ADS_ERROR_NT(nt_status);
150 if (wrapped.length < unwrapped.length) {
152 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
155 /* copy the wrapped blob to the right location */
156 memcpy(wrap->in.buf + 4, unwrapped.data, unwrapped.length);
158 /* set how many bytes must be written to the underlying socket */
159 wrap->in.left = unwrapped.length;
167 static void ads_sasl_gensec_disconnect(struct ads_saslwrap *wrap)
169 struct gensec_security *gensec_security =
170 talloc_get_type_abort(wrap->wrap_private_data,
171 struct gensec_security);
173 TALLOC_FREE(gensec_security);
175 wrap->wrap_ops = NULL;
176 wrap->wrap_private_data = NULL;
179 static const struct ads_saslwrap_ops ads_sasl_gensec_ops = {
181 .wrap = ads_sasl_gensec_wrap,
182 .unwrap = ads_sasl_gensec_unwrap,
183 .disconnect = ads_sasl_gensec_disconnect
187 perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can
188 we fit on one socket??)
190 static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
192 struct cli_credentials *creds,
193 const char *target_service,
194 const char *target_hostname,
195 const DATA_BLOB server_blob)
197 DATA_BLOB blob_in = data_blob_null;
198 DATA_BLOB blob_out = data_blob_null;
202 struct auth_generic_state *auth_generic_state;
203 bool use_spnego_principal = lp_client_use_spnego_principal();
204 const char *sasl_list[] = { sasl, NULL };
205 enum credentials_use_kerberos krb5_state;
207 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
209 nt_status = auth_generic_client_prepare(NULL, &auth_generic_state);
210 if (!NT_STATUS_IS_OK(nt_status)) {
211 return ADS_ERROR_NT(nt_status);
214 nt_status = auth_generic_set_creds(auth_generic_state, creds);
215 if (!NT_STATUS_IS_OK(nt_status)) {
216 return ADS_ERROR_NT(nt_status);
219 if (server_blob.length == 0) {
220 use_spnego_principal = false;
223 krb5_state = cli_credentials_get_kerberos_state(creds);
224 if (krb5_state == CRED_DONT_USE_KERBEROS) {
225 use_spnego_principal = false;
228 if (target_service != NULL) {
229 nt_status = gensec_set_target_service(
230 auth_generic_state->gensec_security,
232 if (!NT_STATUS_IS_OK(nt_status)) {
233 return ADS_ERROR_NT(nt_status);
237 if (target_hostname != NULL) {
238 nt_status = gensec_set_target_hostname(
239 auth_generic_state->gensec_security,
241 if (!NT_STATUS_IS_OK(nt_status)) {
242 return ADS_ERROR_NT(nt_status);
246 if (target_service != NULL && target_hostname != NULL) {
247 use_spnego_principal = false;
250 switch (wrap->wrap_type) {
251 case ADS_SASLWRAP_TYPE_SEAL:
252 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
253 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL);
255 case ADS_SASLWRAP_TYPE_SIGN:
256 if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
257 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
260 * windows servers are broken with sign only,
261 * so we let the NTLMSSP backend to seal here,
262 * via GENSEC_FEATURE_LDAP_STYLE.
264 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN);
265 gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE);
268 case ADS_SASLWRAP_TYPE_PLAIN:
272 nt_status = auth_generic_client_start_by_sasl(auth_generic_state,
274 if (!NT_STATUS_IS_OK(nt_status)) {
275 return ADS_ERROR_NT(nt_status);
278 rc = LDAP_SASL_BIND_IN_PROGRESS;
279 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
280 if (use_spnego_principal) {
281 blob_in = data_blob_dup_talloc(talloc_tos(), server_blob);
282 if (blob_in.length == 0) {
283 TALLOC_FREE(auth_generic_state);
284 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
287 blob_in = data_blob_null;
289 blob_out = data_blob_null;
292 struct berval cred, *scred = NULL;
294 nt_status = gensec_update(auth_generic_state->gensec_security,
295 talloc_tos(), blob_in, &blob_out);
296 data_blob_free(&blob_in);
297 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
298 && !NT_STATUS_IS_OK(nt_status))
300 TALLOC_FREE(auth_generic_state);
301 data_blob_free(&blob_out);
302 return ADS_ERROR_NT(nt_status);
305 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) {
309 cred.bv_val = (char *)blob_out.data;
310 cred.bv_len = blob_out.length;
312 rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred);
313 data_blob_free(&blob_out);
314 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
319 TALLOC_FREE(auth_generic_state);
320 return ADS_ERROR(rc);
323 blob_in = data_blob_talloc(talloc_tos(),
326 if (blob_in.length != scred->bv_len) {
328 TALLOC_FREE(auth_generic_state);
329 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
333 blob_in = data_blob_null;
335 if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) {
340 data_blob_free(&blob_in);
341 data_blob_free(&blob_out);
343 if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) {
346 ok = gensec_have_feature(auth_generic_state->gensec_security,
347 GENSEC_FEATURE_SEAL);
349 DEBUG(0,("The gensec feature sealing request, but unavailable\n"));
350 TALLOC_FREE(auth_generic_state);
351 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
354 ok = gensec_have_feature(auth_generic_state->gensec_security,
355 GENSEC_FEATURE_SIGN);
357 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
358 TALLOC_FREE(auth_generic_state);
359 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
362 } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) {
365 ok = gensec_have_feature(auth_generic_state->gensec_security,
366 GENSEC_FEATURE_SIGN);
368 DEBUG(0,("The gensec feature signing request, but unavailable\n"));
369 TALLOC_FREE(auth_generic_state);
370 return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE);
374 ads->auth.tgs_expire = LONG_MAX;
375 end_nt_time = gensec_expire_time(auth_generic_state->gensec_security);
376 if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) {
378 nttime_to_timeval(&tv, end_nt_time);
379 ads->auth.tgs_expire = tv.tv_sec;
382 if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
384 gensec_max_wrapped_size(auth_generic_state->gensec_security);
385 wrap->out.max_unwrapped =
386 gensec_max_input_size(auth_generic_state->gensec_security);
388 wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped;
390 * Note that we have to truncate this to 0x2C
391 * (taken from a capture with LDAP unbind), as the
392 * signature size is not constant for Kerberos with
395 wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C);
396 wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
397 status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld,
398 &ads_sasl_gensec_ops,
399 auth_generic_state->gensec_security);
400 if (!ADS_ERR_OK(status)) {
401 DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
402 ads_errstr(status)));
403 TALLOC_FREE(auth_generic_state);
406 /* Only keep the gensec_security element around long-term */
407 talloc_steal(NULL, auth_generic_state->gensec_security);
409 TALLOC_FREE(auth_generic_state);
411 return ADS_ERROR(rc);
415 struct ads_service_principal {
424 static void ads_free_service_principal(struct ads_service_principal *p)
426 SAFE_FREE(p->service);
427 SAFE_FREE(p->hostname);
428 SAFE_FREE(p->string);
432 uint32_t minor_status;
433 gss_release_name(&minor_status, &p->name);
439 static ADS_STATUS ads_guess_target(ADS_STRUCT *ads,
444 ADS_STATUS status = ADS_ERROR(LDAP_NO_MEMORY);
451 frame = talloc_stackframe();
453 return ADS_ERROR(LDAP_NO_MEMORY);
456 if (ads->server.realm && ads->server.ldap_server) {
457 server = strlower_talloc(frame, ads->server.ldap_server);
458 if (server == NULL) {
462 realm = strupper_talloc(frame, ads->server.realm);
468 * If we got a name which is bigger than a NetBIOS name,
469 * but isn't a FQDN, create one.
471 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
474 dnsdomain = strlower_talloc(frame, ads->server.realm);
475 if (dnsdomain == NULL) {
479 server = talloc_asprintf(frame,
482 if (server == NULL) {
486 } else if (ads->config.realm && ads->config.ldap_server_name) {
487 server = strlower_talloc(frame, ads->config.ldap_server_name);
488 if (server == NULL) {
492 realm = strupper_talloc(frame, ads->config.realm);
498 * If we got a name which is bigger than a NetBIOS name,
499 * but isn't a FQDN, create one.
501 if (strlen(server) > 15 && strstr(server, ".") == NULL) {
504 dnsdomain = strlower_talloc(frame, ads->server.realm);
505 if (dnsdomain == NULL) {
509 server = talloc_asprintf(frame,
512 if (server == NULL) {
518 if (server == NULL || realm == NULL) {
522 *service = SMB_STRDUP("ldap");
523 if (*service == NULL) {
524 status = ADS_ERROR(LDAP_PARAM_ERROR);
527 *hostname = SMB_STRDUP(server);
528 if (*hostname == NULL) {
530 status = ADS_ERROR(LDAP_PARAM_ERROR);
533 rc = asprintf(&princ, "ldap/%s@%s", server, realm);
534 if (rc == -1 || princ == NULL) {
536 SAFE_FREE(*hostname);
537 status = ADS_ERROR(LDAP_PARAM_ERROR);
543 status = ADS_SUCCESS;
549 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
550 struct ads_service_principal *p)
554 gss_buffer_desc input_name;
555 /* GSS_KRB5_NT_PRINCIPAL_NAME */
556 gss_OID_desc nt_principal =
557 {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
558 uint32_t minor_status;
564 status = ads_guess_target(ads,
568 if (!ADS_ERR_OK(status)) {
573 input_name.value = p->string;
574 input_name.length = strlen(p->string);
576 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
578 ads_free_service_principal(p);
579 return ADS_ERROR_GSS(gss_rc, minor_status);
586 #endif /* HAVE_KRB5 */
589 this performs a SASL/SPNEGO bind
591 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
593 TALLOC_CTX *frame = talloc_stackframe();
594 struct ads_service_principal p = {0};
596 enum credentials_use_kerberos krb5_state;
597 struct cli_credentials *creds;
599 if (ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) {
600 krb5_state = CRED_DONT_USE_KERBEROS;
601 } else if (ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP) {
602 krb5_state = CRED_AUTO_USE_KERBEROS;
604 krb5_state = CRED_MUST_USE_KERBEROS;
607 status = ads_generate_service_principal(ads, &p);
608 if (!ADS_ERR_OK(status)) {
612 creds = ads_sasl_creds_init(frame,
619 status = ADS_ERROR_SYSTEM(ENOMEM);
623 status = ads_sasl_spnego_gensec_bind(ads,
631 if (!ADS_ERR_OK(status)) {
632 DEBUG(1,("ads_sasl_spnego_gensec_bind(GSS-SPNEGO) failed "
633 "for %s/%s with user[%s] realm=[%s]: %s\n",
634 p.service, p.hostname,
637 ads_errstr(status)));
639 ads_free_service_principal(&p);
646 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
648 TALLOC_CTX *frame = talloc_stackframe();
650 struct ads_service_principal p;
651 struct cli_credentials *creds;
653 status = ads_generate_service_principal(ads, &p);
654 if (!ADS_ERR_OK(status)) {
658 creds = ads_sasl_creds_init(frame,
663 CRED_MUST_USE_KERBEROS);
665 status = ADS_ERROR_SYSTEM(ENOMEM);
669 status = ads_sasl_spnego_gensec_bind(ads,
677 ads_free_service_principal(&p);
682 #endif /* HAVE_KRB5 */
684 /* mapping between SASL mechanisms and functions */
687 ADS_STATUS (*fn)(ADS_STRUCT *);
688 } sasl_mechanisms[] = {
689 {"GSS-SPNEGO", ads_sasl_spnego_bind},
691 {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */
696 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
698 const char *attrs[] = {"supportedSASLMechanisms", NULL};
703 struct ads_saslwrap *wrap = &ads->ldap_wrap_data;
705 /* get a list of supported SASL mechanisms */
706 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
707 if (!ADS_ERR_OK(status)) return status;
709 values = ldap_get_values(ads->ldap.ld, res, "supportedSASLMechanisms");
711 if (ads->auth.flags & ADS_AUTH_SASL_SEAL) {
712 wrap->wrap_type = ADS_SASLWRAP_TYPE_SEAL;
713 } else if (ads->auth.flags & ADS_AUTH_SASL_SIGN) {
714 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
716 wrap->wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
719 /* try our supported mechanisms in order */
720 for (i=0;sasl_mechanisms[i].name;i++) {
721 /* see if the server supports it */
722 for (j=0;values && values[j];j++) {
723 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
724 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
726 status = sasl_mechanisms[i].fn(ads);
727 if (status.error_type == ENUM_ADS_ERROR_LDAP &&
728 status.err.rc == LDAP_STRONG_AUTH_REQUIRED &&
729 wrap->wrap_type == ADS_SASLWRAP_TYPE_PLAIN)
731 DEBUG(3,("SASL bin got LDAP_STRONG_AUTH_REQUIRED "
732 "retrying with signing enabled\n"));
733 wrap->wrap_type = ADS_SASLWRAP_TYPE_SIGN;
736 ldap_value_free(values);
743 ldap_value_free(values);
745 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
748 #endif /* HAVE_LDAP */