Require MIT 1.10? (Re: credentials_krb5: use gss_acquire_cred for client-side GSSAPI use case)
Alexander Bokovoy
ab at samba.org
Wed Mar 8 12:27:29 UTC 2017
Hi Stefan,
On ti, 07 maalis 2017, Stefan Metzmacher wrote:
> >>> Sure, but if you want it to be backported to an official 4.6.x release
> >>> they're needed.
> >> Ok, got you.
> > I slept a bit more on this topic and made following:
> > - I integrated Simo's smb_gss_acquire_cred_from() wrapper
> > - Moved smb_gss_krb5_import_cred() to use smb-gss_acquire_cred_from()
> > - Changed gse server and client code to use smb_gss_acquire_cred_from()
> > - Moved libads/sasl.c code to use smb_gss_acquire_cred_from()
> > - Changed MIT krb5 require to 1.10
> > - deprecated a fallback for gss_acquire_cred() in gse code.
> > - backported all of this to 4.6
>
> If you want it backported to 4.6, make the simplest version that
> works for you using smb_gss_krb5_import_cred(), where the
> fallback for the broken gss_krb5_import_cred() is done within
> smb_gss_krb5_import_cred(). Everything else is not acceptable for 4.6,
> sorry.
>
> We should just discuss that simplest version *only* now. Once it's in master
> and can be backported, we can think about gss_acquire_cred_from() for
> master.
I have reworked 4.6 backport to incorporate the fallback to
smb_gss_krb5_import_cred() wrapper. The backport has no
gss_acquire_cred_from() in the main code, only in a wrapper -- if it is
available. The wrapper for the case when gss_acquire_cred_from() is not
available still uses gss_krb5_import_cred() and gss_acquire_cred() --
with a fallback to the latter in case we are setting up an acceptor
without a keytab principal specifying.
I haven't backported bumping requirements to MIT 1.10.
> > Now we only have auth/credentials/credentials_krb5.c using
> > smb_gss_krb5_import_cred() wrapper with explicit ccache handles.
> > On MIT krb5 1.10 or later all code paths lead to gss_acquire_cred_from().
>
> gss_acquire_cred_from() is available from 1.11
In the main patchset I use Simo's smb_gss_acquire_cred_from() wrapper.
For Heimdal and MIT < 1.11 it does fall back to use
gss_krb5_import_cred() and gss_acquire_cred(). However, I did remove the
fallback for broken gss_krb5_import_cred() in MIT 1.9 as I bumped
requirement for MIT krb5 to 1.10. The actual fix for this problem was in
MIT krb5 1.9.2, but I think we are fine with 1.10 as I found out there
are basically no 1.9 builds around in supported Linux and *BSD
distributions anymore.
--
/ Alexander Bokovoy
-------------- next part --------------
>From 46261d5ffda03d50c893ddf58fd35bb0e2b4a656 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 17:08:09 +0200
Subject: [PATCH 01/13] gssapi: check for gss_acquire_cred_from
---
wscript_configure_system_mitkrb5 | 1 +
1 file changed, 1 insertion(+)
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 06a9821..d3e8ebf 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -92,6 +92,7 @@ conf.CHECK_FUNCS_IN('''
gsskrb5_extract_authz_data_from_sec_context
gss_krb5_export_lucid_sec_context
gss_import_cred gss_export_cred
+ gss_acquire_cred_from
''', 'gssapi gssapi_krb5')
conf.CHECK_VARIABLE('GSS_KRB5_CRED_NO_CI_FLAGS_X', headers=possible_gssapi_headers)
conf.CHECK_FUNCS_IN('krb5_mk_req_extended krb5_kt_compare', 'krb5')
--
2.9.3
>From 6c1c42f8e459128cdd3e514843133804cf74e723 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:14:57 +0200
Subject: [PATCH 02/13] lib/krb5_wrap: add smb_gss_krb5_import_cred wrapper
Wrap gss_krb5_import_cred() to allow re-implementing it with
gss_acquire_cred_from() for newer MIT versions. gss_acquire_cred_from()
works fine with GSSAPI interposer (GSS-proxy) while
gss_krb5_import_cred() is not interposed yet.
The wrapper has additional parameter, krb5_context handle, to facilitate
with credentials cache name discovery. All our callers to
gss_krb5_import_cred() already have krb5 context handy.
---
lib/krb5_wrap/gss_samba.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++
lib/krb5_wrap/gss_samba.h | 13 +++++
2 files changed, 134 insertions(+)
diff --git a/lib/krb5_wrap/gss_samba.c b/lib/krb5_wrap/gss_samba.c
index b444633..0f24a39 100644
--- a/lib/krb5_wrap/gss_samba.c
+++ b/lib/krb5_wrap/gss_samba.c
@@ -48,4 +48,125 @@ int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid)
}
#endif /* !HAVE_GSS_OID_EQUAL */
+
+/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
+ * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
+ * interposed by GSSPROXY while gss_krb5_import_cred() is not.
+ *
+ * This wrapper requires a proper krb5_context to resolve ccache name.
+ * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
+uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
+ krb5_ccache id, krb5_principal keytab_principal,
+ krb5_keytab keytab, gss_cred_id_t *cred)
+{
+ uint32_t major_status = 0;
+ uint32_t minor = 0;
+
+#if HAVE_GSS_ACQUIRE_CRED_FROM
+ gss_key_value_element_desc ccache_element = {
+ .key = "ccache",
+ .value = NULL,
+ };
+
+ gss_key_value_element_desc keytab_element = {
+ .key = "keytab",
+ .value = NULL,
+ };
+
+ gss_key_value_element_desc elements[2];
+
+ gss_key_value_set_desc cred_store = {
+ .elements = &ccache_element,
+ .count = 1,
+ };
+
+ gss_OID_set mech_set = GSS_C_NO_OID_SET;
+ gss_cred_usage_t cred_usage = GSS_C_INITIATE;
+ gss_name_t name = NULL;
+ gss_buffer_desc pr_name = {
+ .value = NULL,
+ .length = 0,
+ };
+
+ if (id != NULL) {
+ major_status = krb5_cc_get_full_name(ctx,
+ id,
+ discard_const(&ccache_element.value));
+ if (major_status != 0) {
+ return major_status;
+ }
+ }
+
+ if (keytab != NULL) {
+ keytab_element.value = malloc(4096);
+ if (!keytab_element.value) {
+ return ENOMEM;
+ }
+ major_status = krb5_kt_get_name(ctx,
+ keytab,
+ discard_const(keytab_element.value), 4096);
+ if (major_status != 0) {
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ cred_usage = GSS_C_ACCEPT;
+ cred_store.elements = &keytab_element;
+
+ if (keytab_principal != NULL) {
+ major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
+ if (major_status != 0) {
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ pr_name.length = strlen(pr_name.value);
+
+ major_status = gss_import_name(minor_status,
+ &pr_name,
+ discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
+ &name);
+ if (major_status != 0) {
+ krb5_free_unparsed_name(ctx, pr_name.value);
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ }
+ }
+
+ if (id != NULL && keytab != NULL) {
+ elements[0] = ccache_element;
+ elements[1] = keytab_element;
+
+ cred_store.elements = elements;
+ cred_store.count = 2;
+ cred_usage = GSS_C_BOTH;
+ }
+
+ major_status = gss_acquire_cred_from(minor_status,
+ name,
+ 0,
+ mech_set,
+ cred_usage,
+ &cred_store,
+ cred,
+ NULL,
+ NULL);
+
+ if (pr_name.value != NULL) {
+ (void)gss_release_name(&minor, &name);
+ krb5_free_unparsed_name(ctx, pr_name.value);
+ }
+ if (keytab_element.value != NULL) {
+ free(discard_const(keytab_element.value));
+ }
+ krb5_free_string(ctx, discard_const(ccache_element.value));
+#else
+ major_status = gss_krb5_import_cred(minor_status,
+ id,
+ keytab_principal,
+ keytab, cred);
+#endif
+ return major_status;
+}
+
+
#endif /* HAVE_GSSAPI */
diff --git a/lib/krb5_wrap/gss_samba.h b/lib/krb5_wrap/gss_samba.h
index 5319932..89aee34 100644
--- a/lib/krb5_wrap/gss_samba.h
+++ b/lib/krb5_wrap/gss_samba.h
@@ -25,6 +25,7 @@
#ifdef HAVE_GSSAPI
#include "system/gssapi.h"
+#include "krb5_samba.h"
#if defined(HAVE_GSS_OID_EQUAL)
#define smb_gss_oid_equal gss_oid_equal
@@ -32,5 +33,17 @@
int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid);
#endif /* HAVE_GSS_OID_EQUAL */
+/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
+ * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
+ * interposed by GSS-proxy while gss_krb5_import_cred() is not.
+ *
+ * This wrapper requires a proper krb5_context to resolve the ccache name for
+ * gss_acquire_cred_from().
+ *
+ * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
+uint32_t smb_gss_krb5_import_cred(OM_uint32 *minor_status, krb5_context ctx,
+ krb5_ccache id, krb5_principal keytab_principal,
+ krb5_keytab keytab, gss_cred_id_t *cred);
+
#endif /* HAVE_GSSAPI */
#endif /* _GSS_SAMBA_H */
--
2.9.3
>From f7a266eddc1385af8a5ac633787e0c337c81a65c Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:57:13 +0200
Subject: [PATCH 03/13] credentials_krb5: convert to use
smb_gss_krb5_import_cred
---
auth/credentials/credentials_krb5.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c
index d2a655e..6544e42 100644
--- a/auth/credentials/credentials_krb5.c
+++ b/auth/credentials/credentials_krb5.c
@@ -717,8 +717,9 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
return ENOMEM;
}
- maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
+ ccache->ccache, NULL, NULL,
+ &gcc->creds);
if ((maj_stat == GSS_S_FAILURE) &&
(min_stat == (OM_uint32)KRB5_CC_END ||
min_stat == (OM_uint32)KRB5_CC_NOTFOUND ||
@@ -735,8 +736,9 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
return ret;
}
- maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
+ ccache->ccache, NULL, NULL,
+ &gcc->creds);
}
@@ -747,7 +749,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
} else {
ret = EINVAL;
}
- (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
+ (*error_string) = talloc_asprintf(cred, "smb_gss_krb5_import_cred failed: %s", error_message(ret));
return ret;
}
@@ -1215,12 +1217,14 @@ _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
if (ktc->password_based || obtained < CRED_SPECIFIED) {
/* This creates a GSSAPI cred_id_t for match-by-key with only the keytab set */
- maj_stat = gss_krb5_import_cred(&min_stat, NULL, NULL, ktc->keytab,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, smb_krb5_context->krb5_context,
+ NULL, NULL, ktc->keytab,
+ &gcc->creds);
} else {
/* This creates a GSSAPI cred_id_t with the principal and keytab set, matching by name */
- maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, smb_krb5_context->krb5_context,
+ NULL, princ, ktc->keytab,
+ &gcc->creds);
}
if (maj_stat) {
if (min_stat) {
--
2.9.3
>From c6142eeaeb48397b220ad68118f1139d9d40d36d Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:57:50 +0200
Subject: [PATCH 04/13] libads: convert to use smb_gss_krb5_import_cred
---
source3/libads/sasl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index cb630fa..ab79f70 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -371,7 +371,7 @@ static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
goto done;
}
- maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
+ maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
if (maj != GSS_S_COMPLETE) {
status = ADS_ERROR_GSS(maj, min);
goto done;
--
2.9.3
>From c9188964fb1ba67add94bc4926b82b05fbe6ce3b Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:58:14 +0200
Subject: [PATCH 05/13] s3-gse: convert to use smb_gss_krb5_import_cred
---
source3/librpc/crypto/gse.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index abf20bc..f4238f3 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -252,11 +252,12 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
/* TODO: get krb5 ticket using username/password, if no valid
* one already available in ccache */
- gss_maj = gss_krb5_import_cred(&gss_min,
- gse_ctx->ccache,
- NULL, /* keytab_principal */
- NULL, /* keytab */
- &gse_ctx->creds);
+ gss_maj = smb_gss_krb5_import_cred(&gss_min,
+ gse_ctx->k5ctx,
+ gse_ctx->ccache,
+ NULL, /* keytab_principal */
+ NULL, /* keytab */
+ &gse_ctx->creds);
if (gss_maj) {
char *ccache = NULL;
int kret;
@@ -268,7 +269,7 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
ccache = NULL;
}
- DEBUG(5, ("gss_krb5_import_cred ccache[%s] failed with [%s] -"
+ DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -"
"the caller may retry after a kinit.\n",
ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
SAFE_FREE(ccache);
@@ -430,12 +431,13 @@ static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
}
/* This creates a GSSAPI cred_id_t with the keytab set */
- gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab,
- &gse_ctx->creds);
+ gss_maj = smb_gss_krb5_import_cred(&gss_min, gse_ctx->k5ctx,
+ NULL, NULL, gse_ctx->keytab,
+ &gse_ctx->creds);
if (gss_maj != 0
&& gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
- DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
+ DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
gse_errstr(gse_ctx, gss_maj, gss_min)));
status = NT_STATUS_INTERNAL_ERROR;
goto done;
--
2.9.3
>From d35e1c85330d23ba96bcd3fc1713e503afe80cb0 Mon Sep 17 00:00:00 2001
From: Simo Sorce <idra at samba.org>
Date: Sun, 5 Mar 2017 13:15:54 -0500
Subject: [PATCH 06/13] Add fallback for gss_acquire_cred_from
We want to use gss_acquire_cred_from() so modern MIT versions can
interpose applications and provide privilege separation.
This patch implements a compatibility functions that falls back top use
gss_krb5_import_cred() when a native gss_acquire_cred_from() function is
not available.
Signed-off-by: Simo Sorce <idra at samba.org>
---
lib/krb5_wrap/gss_samba.c | 118 +++++++++++++++++++++++++++++++++++++++++++++-
lib/krb5_wrap/gss_samba.h | 27 +++++++++++
2 files changed, 144 insertions(+), 1 deletion(-)
diff --git a/lib/krb5_wrap/gss_samba.c b/lib/krb5_wrap/gss_samba.c
index 0f24a39..4e9f02b 100644
--- a/lib/krb5_wrap/gss_samba.c
+++ b/lib/krb5_wrap/gss_samba.c
@@ -21,6 +21,7 @@
#include "includes.h"
#include "gss_samba.h"
+#include "krb5_samba.h"
#ifdef HAVE_GSSAPI
@@ -48,6 +49,122 @@ int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid)
}
#endif /* !HAVE_GSS_OID_EQUAL */
+/* Let's wrap the old gss_krb5_import_cred() into a modern GSSAPI intrerface
+ * that is used by default. */
+uint32_t smb_gss_acquire_cred_from(uint32_t *minor_status,
+ gss_name_t desired_name,
+ uint32_t time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ uint32_t *time_rec)
+{
+#if HAVE_GSS_ACQUIRE_CRED_FROM
+ return gss_acquire_cred_from(minor_status, desired_name, time_req,
+ desired_mechs, cred_usage, cred_store,
+ output_cred_handle, actual_mechs, time_rec);
+#else /* HAVE_GSS_ACQUIRE_CRED_FROM */
+ uint32_t maj, min, tmp;
+ gss_cred_id_t cred = NULL;
+ const char *ccache_name = NULL;
+ const char *keytab_name = NULL;
+ krb5_context context = NULL;
+ krb5_principal princ = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_keytab keytab = NULL;
+ krb5_error_code ret;
+
+ if (!cred_store || cred_store->count == 0) {
+ return gss_acquire_cred(minor_status, desired_name, time_req,
+ desired_mechs, cred_usage, output_cred_handle,
+ actual_mechs, time_rec);
+ }
+
+ if (desired_mech && !gss_oid_equal(desired_mech, gss_mech_krb5)) {
+ return GSS_S_BAD_MECH;
+ }
+
+ ret = krb5_init_context(&context);
+ if (ret) {
+ min = ret;
+ maj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if (desired_name) {
+ gss_buffer_desc buf = GSS_C_EMPTY_BUFFER;
+
+ maj = gss_display_name(&min, desired_name, &buf, NULL);
+ if (maj == GSS_S_COMPLETE) {
+ char name[buf.length + 1];
+
+ memcpy(name, buf.value, buf.length);
+ ret = krb5_parse_name(context, name, &princ);
+ if (ret) {
+ min = ret;
+ maj = GSS_S_FAILURE;
+ }
+
+ (void)gss_release_buffer(&tmp, &buf);
+ }
+ if (maj != GSS_S_COMPLETE) goto done;
+ }
+
+ for (uint32_t i; cred_store && i < cred_store->count; i++) {
+ if (strcmp(cred_store->elements[i].key, "ccache") == 0) {
+ ccache_name = cred_store->elements[i].value;
+ } else if (cred_usage == GSS_C_INITIATE &&
+ strcmp(cred_store->elements[i].key, "client_keytab") == 0) {
+ keytab_name = cred_store->elements[i].value;
+ } else if (cred_usage != GSS_C_INITIATE &&
+ strcmp(cred_store->elements[i].key, "keytab") == 0) {
+ keytab_name = cred_store->elements[i].value;
+ }
+ }
+
+ if (ccache_name) {
+ ret = krb5_cc_resolve(context, ccache_name, &ccache);
+ } else {
+ ret = krb5_cc_default(context, &ccache);
+ }
+ if (ret) {
+ min = ret;
+ maj = GSS_S_FAILURE;
+ goto done;
+ }
+
+ if (keytab_name) {
+ ret = krb5_kt_resolve(context, keytab_name, &keytab);
+ if (ret) {
+ min = ret;
+ maj = GSS_S_FAILURE;
+ goto done;
+ }
+ }
+
+ maj = gss_krb5_import_cred(&min, ccache, princ, keytab, &cred);
+ if (maj != GSS_S_COMPLETE) goto done;
+
+ if (actual_mechs || time_rec) {
+ maj = gss_inquire_cred(&min, cred, NULL, time_rec, NULL, actual_mechs);
+ }
+
+done:
+ if (context) {
+ krb5_free_principal(context, princ);
+ if (keytab) krb5_kt_close(context, keytab);
+ krb5_free_context(context);
+ }
+ if (maj != GSS_S_COMPLETE && cred != NULL) {
+ (void)gss_release_cred(&tmp, &cred);
+ }
+ *output_cred_handle = cred;
+ *minor_status = min;
+ return maj;
+#endif /* HAVE_GSS_ACQUIRE_CRED_FROM */
+}
/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
* if this GSSAPI extension is available. gss_acquire_cred_from() is properly
@@ -168,5 +285,4 @@ uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
return major_status;
}
-
#endif /* HAVE_GSSAPI */
diff --git a/lib/krb5_wrap/gss_samba.h b/lib/krb5_wrap/gss_samba.h
index 89aee34..bc4dd69 100644
--- a/lib/krb5_wrap/gss_samba.h
+++ b/lib/krb5_wrap/gss_samba.h
@@ -45,5 +45,32 @@ uint32_t smb_gss_krb5_import_cred(OM_uint32 *minor_status, krb5_context ctx,
krb5_ccache id, krb5_principal keytab_principal,
krb5_keytab keytab, gss_cred_id_t *cred);
+#ifndef HAVE_GSS_ACQUIRE_CRED_FROM
+struct gss_key_value_element_struct {
+ const char *key;
+ const char *value;
+};
+typedef struct gss_key_value_element_struct gss_key_value_element_desc;
+
+struct gss_key_value_set_struct {
+ OM_uint32 count;
+ gss_key_value_element_desc *elements;
+};
+typedef struct gss_key_value_set_struct gss_key_value_set_desc;
+typedef const gss_key_value_set_desc *gss_const_key_value_set_t;
+#endif /* !HAVE_GSS_ACQUIRE_CRED_FROM */
+
+/* wrapper to get gss_acquire_cred_from() on Kerberos versions that don't have
+ * this extension. */
+uint32_t smb_gss_acquire_cred_from(uint32_t *minor_status,
+ gss_name_t desired_name,
+ uint32_t time_req,
+ gss_OID_set desired_mechs,
+ gss_cred_usage_t cred_usage,
+ gss_const_key_value_set_t cred_store,
+ gss_cred_id_t *output_cred_handle,
+ gss_OID_set *actual_mechs,
+ uint32_t *time_rec);
+
#endif /* HAVE_GSSAPI */
#endif /* _GSS_SAMBA_H */
--
2.9.3
>From d112ad4c0f854b0b1bb8c66b4e284b4785bd03a5 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 10:59:32 +0200
Subject: [PATCH 07/13] krb5_wrap/gss_samba: reuse smb_gss_acquire_cred_from
for smb_gss_krb5_import_cred
---
lib/krb5_wrap/gss_samba.c | 29 ++++++++++-------------------
1 file changed, 10 insertions(+), 19 deletions(-)
diff --git a/lib/krb5_wrap/gss_samba.c b/lib/krb5_wrap/gss_samba.c
index 4e9f02b..ce15a57 100644
--- a/lib/krb5_wrap/gss_samba.c
+++ b/lib/krb5_wrap/gss_samba.c
@@ -166,9 +166,7 @@ done:
#endif /* HAVE_GSS_ACQUIRE_CRED_FROM */
}
-/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
- * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
- * interposed by GSSPROXY while gss_krb5_import_cred() is not.
+/* wrapper around gss_krb5_import_cred() that uses smb_gss_acquire_cred_from()
*
* This wrapper requires a proper krb5_context to resolve ccache name.
* All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
@@ -179,7 +177,6 @@ uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
uint32_t major_status = 0;
uint32_t minor = 0;
-#if HAVE_GSS_ACQUIRE_CRED_FROM
gss_key_value_element_desc ccache_element = {
.key = "ccache",
.value = NULL,
@@ -258,15 +255,15 @@ uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
cred_usage = GSS_C_BOTH;
}
- major_status = gss_acquire_cred_from(minor_status,
- name,
- 0,
- mech_set,
- cred_usage,
- &cred_store,
- cred,
- NULL,
- NULL);
+ major_status = smb_gss_acquire_cred_from(minor_status,
+ name,
+ 0,
+ mech_set,
+ cred_usage,
+ &cred_store,
+ cred,
+ NULL,
+ NULL);
if (pr_name.value != NULL) {
(void)gss_release_name(&minor, &name);
@@ -276,12 +273,6 @@ uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
free(discard_const(keytab_element.value));
}
krb5_free_string(ctx, discard_const(ccache_element.value));
-#else
- major_status = gss_krb5_import_cred(minor_status,
- id,
- keytab_principal,
- keytab, cred);
-#endif
return major_status;
}
--
2.9.3
>From e6295c863cfd2bd58da8c101488a39e91b2faf5d Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 11:03:32 +0200
Subject: [PATCH 08/13] s3-gse_krb5: move server keytab definition to the
gse_krb5.h
---
source3/librpc/crypto/gse_krb5.c | 1 -
source3/librpc/crypto/gse_krb5.h | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/source3/librpc/crypto/gse_krb5.c b/source3/librpc/crypto/gse_krb5.c
index 703d1b4..db99001 100644
--- a/source3/librpc/crypto/gse_krb5.c
+++ b/source3/librpc/crypto/gse_krb5.c
@@ -203,7 +203,6 @@ out:
return ret;
}
-#define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
#define CLEARTEXT_PRIV_ENCTYPE -99
static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx,
diff --git a/source3/librpc/crypto/gse_krb5.h b/source3/librpc/crypto/gse_krb5.h
index ea789c9..4193385 100644
--- a/source3/librpc/crypto/gse_krb5.h
+++ b/source3/librpc/crypto/gse_krb5.h
@@ -22,6 +22,7 @@
#ifdef HAVE_KRB5
+#define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab"
krb5_error_code gse_krb5_get_server_keytab(krb5_context krbctx,
krb5_keytab *keytab);
--
2.9.3
>From f3cfcbb376e5a6c9900396ba679ba6ce6ee75da8 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 11:35:25 +0200
Subject: [PATCH 09/13] s3-gse: use smb_gss_acquire_crde_from instead of
smb_gss_krb5_import_cred
---
source3/librpc/crypto/gse.c | 94 +++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 50 deletions(-)
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index f4238f3..6701ae5 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -416,6 +416,15 @@ static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
OM_uint32 gss_maj, gss_min;
krb5_error_code ret;
NTSTATUS status;
+ gss_key_value_element_desc keytab_element = {
+ .key = "keytab",
+ .value = SRV_MEM_KEYTAB_NAME,
+ };
+ gss_key_value_set_desc cred_store = {
+ .elements = &keytab_element,
+ .count = 1,
+ };
+ gss_OID_set_desc mech_set;
status = gse_context_init(mem_ctx, do_sign, do_seal,
NULL, add_gss_c_flags, &gse_ctx);
@@ -430,66 +439,51 @@ static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
goto done;
}
- /* This creates a GSSAPI cred_id_t with the keytab set */
- gss_maj = smb_gss_krb5_import_cred(&gss_min, gse_ctx->k5ctx,
- NULL, NULL, gse_ctx->keytab,
- &gse_ctx->creds);
-
- if (gss_maj != 0
- && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
- DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
- gse_errstr(gse_ctx, gss_maj, gss_min)));
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
+ mech_set.count = 1;
+ mech_set.elements = &gse_ctx->gss_mech;
- /* This is the error the MIT krb5 1.9 gives when it
- * implements the function, but we do not specify the
- * principal. However, when we specify the principal
- * as host$@REALM the GSS acceptor fails with 'wrong
- * principal in request'. Work around the issue by
- * falling back to the alternate approach below. */
- } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
- /* FIXME!!!
- * This call sets the default keytab for the whole server, not
- * just for this context. Need to find a way that does not alter
- * the state of the whole server ... */
- {
- const char *ktname;
- gss_OID_set_desc mech_set;
-
- ret = smb_krb5_kt_get_name(gse_ctx, gse_ctx->k5ctx,
- gse_ctx->keytab, &ktname);
- if (ret) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
+ gss_maj = smb_gss_acquire_cred_from(&gss_min,
+ GSS_C_NO_NAME,
+ 0,
+ &mech_set,
+ GSS_C_ACCEPT,
+ &cred_store,
+ &gse_ctx->creds,
+ NULL,
+ NULL);
- ret = gsskrb5_register_acceptor_identity(ktname);
+ /* smb_gss_acquire_cred_from() wrapper may fall back to use
+ * gss_krb5_import_cred() and on MIT krb5 1.9 that one may
+ * return this error code when we do not specify the name.
+ *
+ * As an alternative approach, register global server keytab
+ * but this affects all contexts in the server.
+ *
+ * The code is fixed in MIT krb5 1.10 or later. */
+ if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
+ ret = gsskrb5_register_acceptor_identity(SRV_MEM_KEYTAB_NAME);
if (ret) {
status = NT_STATUS_INTERNAL_ERROR;
goto done;
}
- mech_set.count = 1;
- mech_set.elements = &gse_ctx->gss_mech;
-
- gss_maj = gss_acquire_cred(&gss_min,
- GSS_C_NO_NAME,
- GSS_C_INDEFINITE,
- &mech_set,
- GSS_C_ACCEPT,
- &gse_ctx->creds,
- NULL, NULL);
-
- if (gss_maj) {
- DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
- gse_errstr(gse_ctx, gss_maj, gss_min)));
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
+ gss_maj = smb_gss_acquire_cred_from(&gss_min,
+ GSS_C_NO_NAME,
+ GSS_C_INDEFINITE,
+ &mech_set,
+ GSS_C_ACCEPT,
+ &cred_store,
+ &gse_ctx->creds,
+ NULL,
+ NULL);
}
status = NT_STATUS_OK;
+ if (gss_maj != 0) {
+ DEBUG(0, ("smb_gss_acquire_cred_from failed with [%s]\n",
+ gse_errstr(gse_ctx, gss_maj, gss_min)));
+ status = NT_STATUS_INTERNAL_ERROR;
+ }
done:
if (!NT_STATUS_IS_OK(status)) {
--
2.9.3
>From c76ce54f85c05f4d8daea058761884b527ff53d2 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 11:37:09 +0200
Subject: [PATCH 10/13] wscript: for MIT krb5, require at least version 1.10
MIT krb5 1.10 has a number of important fixes, including a fix for
gss_krb5_import_cred() when initializing from a keytab without
explicitly specified Kerberos principal.
The code that broke gss_krb5_import_cred() in MIT 1.9 was later fixed[1]
with bd18687a705a8a6cdcb7c140764d1a7c6a3381b5 and finally the whole code
path was removed with 889d3ca4c482f730cd194f2d83c41d70bc615a67
Both changes were released in MIT 1.10.
RHEL 6 has MIT krb5 1.10.3. Ubuntu and Debian have 1.10 too, starting
with Precise, that's 5 stable releases ago for Ubuntu, and Wheezy for
Debian.
https://packages.debian.org/search?keywords=krb5&searchon=sourcenames&suite=all§ion=all
On FreeBSD we have at least MIT 1.13 since FreeBSD 8.4:
http://portsmon.freebsd.org/portoverview.py?category=security&portname=krb5&wildcard=
[1] See Greg's answer to Andrew about broken code in 2011:
https://lists.samba.org/archive/samba-technical/2011-July/078635.html
Thus, we can safely require at least MIT krb5 1.10 for environments
released during last five years.
---
wscript_configure_system_mitkrb5 | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index d3e8ebf..678f765 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -51,8 +51,8 @@ if conf.env.KRB5_CONFIG:
last_digit = kversion_split[-1].split('-')[0]
kversion_split[-1] = last_digit
kversion_check = map(int, kversion_split)
- if kversion_check < [1, 9]:
- Logs.error('ERROR: MIT krb5 build requires at least 1.9.0. %s is found and cannot be used' % (kversion))
+ if kversion_check < [1, 10]:
+ Logs.error('ERROR: MIT krb5 build requires at least 1.10.0. %s is found and cannot be used' % (kversion))
Logs.error('ERROR: You may try to build with embedded Heimdal Kerebros by not specifying --with-system-mitkrb5')
sys.exit(1)
else:
--
2.9.3
>From aa11f21e9e38dc51bd36f9c4812ef3b385e751f5 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 11:43:07 +0200
Subject: [PATCH 11/13] s3-gse: remove fallback for broken gss_krb5_import_cred
in MIT kbr5 1.9
Now that we require at least MIT krb5 1.10, remove the fallback for the
broken gss_krb5_import_cred.
---
source3/librpc/crypto/gse.c | 26 --------------------------
1 file changed, 26 deletions(-)
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index 6701ae5..c962b7c 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -452,32 +452,6 @@ static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
NULL,
NULL);
- /* smb_gss_acquire_cred_from() wrapper may fall back to use
- * gss_krb5_import_cred() and on MIT krb5 1.9 that one may
- * return this error code when we do not specify the name.
- *
- * As an alternative approach, register global server keytab
- * but this affects all contexts in the server.
- *
- * The code is fixed in MIT krb5 1.10 or later. */
- if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
- ret = gsskrb5_register_acceptor_identity(SRV_MEM_KEYTAB_NAME);
- if (ret) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
-
- gss_maj = smb_gss_acquire_cred_from(&gss_min,
- GSS_C_NO_NAME,
- GSS_C_INDEFINITE,
- &mech_set,
- GSS_C_ACCEPT,
- &cred_store,
- &gse_ctx->creds,
- NULL,
- NULL);
- }
-
status = NT_STATUS_OK;
if (gss_maj != 0) {
DEBUG(0, ("smb_gss_acquire_cred_from failed with [%s]\n",
--
2.9.3
>From 2a8ea20cf333f05a53a7d412c9073a53a20746b1 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 11:57:53 +0200
Subject: [PATCH 12/13] s3-gse: use smb_gss_acquire_cred_from for gse client as
well
---
source3/librpc/crypto/gse.c | 42 +++++++++++++++++++++++-------------------
1 file changed, 23 insertions(+), 19 deletions(-)
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index c962b7c..1656179 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -209,6 +209,15 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
#endif
NTSTATUS status;
+ gss_key_value_element_desc ccache_element = {
+ .key = "ccache",
+ .value = ccache_name,
+ };
+ gss_key_value_set_desc cred_store = {
+ .elements = &ccache_element,
+ .count = 1,
+ };
+ gss_OID_set_desc mech_set;
if (!server || !service) {
return NT_STATUS_INVALID_PARAMETER;
@@ -252,27 +261,22 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
/* TODO: get krb5 ticket using username/password, if no valid
* one already available in ccache */
- gss_maj = smb_gss_krb5_import_cred(&gss_min,
- gse_ctx->k5ctx,
- gse_ctx->ccache,
- NULL, /* keytab_principal */
- NULL, /* keytab */
- &gse_ctx->creds);
- if (gss_maj) {
- char *ccache = NULL;
- int kret;
-
- kret = krb5_cc_get_full_name(gse_ctx->k5ctx,
- gse_ctx->ccache,
- &ccache);
- if (kret != 0) {
- ccache = NULL;
- }
+ mech_set.count = 1;
+ mech_set.elements = &gse_ctx->gss_mech;
- DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -"
+ gss_maj = smb_gss_acquire_cred_from(&gss_min,
+ GSS_C_NO_NAME,
+ 0,
+ &mech_set,
+ GSS_C_INITIATE,
+ &cred_store,
+ &gse_ctx->creds,
+ NULL,
+ NULL);
+ if (gss_maj) {
+ DEBUG(5, ("smb_gss_acquire_cred_from ccache[%s] failed with [%s] -"
"the caller may retry after a kinit.\n",
- ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
- SAFE_FREE(ccache);
+ ccache_name, gse_errstr(gse_ctx, gss_maj, gss_min)));
status = NT_STATUS_INTERNAL_ERROR;
goto err_out;
}
--
2.9.3
>From c836e6c674501ef1f17c5cc592b7007ab81ec966 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Tue, 7 Mar 2017 12:14:03 +0200
Subject: [PATCH 13/13] s3-libads/sasl.c: use smb_gss_acquire_cred_from()
---
source3/libads/sasl.c | 43 ++++++++++++++++++++-----------------------
1 file changed, 20 insertions(+), 23 deletions(-)
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index ab79f70..7d1852e 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -349,10 +349,15 @@ static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads,
static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
{
ADS_STATUS status;
- krb5_context kctx;
- krb5_error_code kerr;
- krb5_ccache kccache = NULL;
uint32_t maj, min;
+ gss_key_value_element_desc ccache_element = {
+ .key = "ccache",
+ .value = NULL,
+ };
+ gss_key_value_set_desc cred_store = {
+ .elements = &ccache_element,
+ .count = 1,
+ };
*cred = GSS_C_NO_CREDENTIAL;
@@ -360,30 +365,22 @@ static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
return ADS_SUCCESS;
}
- kerr = krb5_init_context(&kctx);
- if (kerr) {
- return ADS_ERROR_KRB5(kerr);
- }
-
- kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
- if (kerr) {
- status = ADS_ERROR_KRB5(kerr);
- goto done;
- }
-
- maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
+ ccache_element.value = ads->auth.ccache_name;
+
+ maj = smb_gss_acquire_cred_from(&min,
+ GSS_C_NO_NAME,
+ 0,
+ GSS_C_NO_OID_SET,
+ GSS_C_INITIATE,
+ &cred_store,
+ cred,
+ NULL,
+ NULL);
+ status = ADS_SUCCESS;
if (maj != GSS_S_COMPLETE) {
status = ADS_ERROR_GSS(maj, min);
- goto done;
}
- status = ADS_SUCCESS;
-
-done:
- if (!ADS_ERR_OK(status) && kccache != NULL) {
- krb5_cc_close(kctx, kccache);
- }
- krb5_free_context(kctx);
return status;
}
--
2.9.3
-------------- next part --------------
>From fdf1a5e1375b40aceab2dc29579596b98811c416 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 17:08:09 +0200
Subject: [PATCH 1/6] gssapi: check for gss_acquire_cred_from
---
wscript_configure_system_mitkrb5 | 1 +
1 file changed, 1 insertion(+)
diff --git a/wscript_configure_system_mitkrb5 b/wscript_configure_system_mitkrb5
index 06a9821..d3e8ebf 100644
--- a/wscript_configure_system_mitkrb5
+++ b/wscript_configure_system_mitkrb5
@@ -92,6 +92,7 @@ conf.CHECK_FUNCS_IN('''
gsskrb5_extract_authz_data_from_sec_context
gss_krb5_export_lucid_sec_context
gss_import_cred gss_export_cred
+ gss_acquire_cred_from
''', 'gssapi gssapi_krb5')
conf.CHECK_VARIABLE('GSS_KRB5_CRED_NO_CI_FLAGS_X', headers=possible_gssapi_headers)
conf.CHECK_FUNCS_IN('krb5_mk_req_extended krb5_kt_compare', 'krb5')
--
2.9.3
>From 16436ce004f50ac84193cb493a078d51d972a2a2 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:14:57 +0200
Subject: [PATCH 2/6] lib/krb5_wrap: add smb_gss_krb5_import_cred wrapper
Wrap gss_krb5_import_cred() to allow re-implementing it with
gss_acquire_cred_from() for newer MIT versions. gss_acquire_cred_from()
works fine with GSSAPI interposer (GSS-proxy) while
gss_krb5_import_cred() is not interposed yet.
The wrapper has additional parameter, krb5_context handle, to facilitate
with credentials cache name discovery. All our callers to
gss_krb5_import_cred() already have krb5 context handy.
---
lib/krb5_wrap/gss_samba.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++
lib/krb5_wrap/gss_samba.h | 13 +++++
2 files changed, 134 insertions(+)
diff --git a/lib/krb5_wrap/gss_samba.c b/lib/krb5_wrap/gss_samba.c
index b444633..757ffc5 100644
--- a/lib/krb5_wrap/gss_samba.c
+++ b/lib/krb5_wrap/gss_samba.c
@@ -48,4 +48,125 @@ int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid)
}
#endif /* !HAVE_GSS_OID_EQUAL */
+
+/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
+ * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
+ * interposed by GSSPROXY while gss_krb5_import_cred() is not.
+ *
+ * This wrapper requires a proper krb5_context to resolve ccache name.
+ * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
+uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
+ krb5_ccache id, krb5_principal keytab_principal,
+ krb5_keytab keytab, gss_cred_id_t *cred)
+{
+ uint32_t major_status = 0;
+
+#if HAVE_GSS_ACQUIRE_CRED_FROM
+ uint32_t minor = 0;
+ gss_key_value_element_desc ccache_element = {
+ .key = "ccache",
+ .value = NULL,
+ };
+
+ gss_key_value_element_desc keytab_element = {
+ .key = "keytab",
+ .value = NULL,
+ };
+
+ gss_key_value_element_desc elements[2];
+
+ gss_key_value_set_desc cred_store = {
+ .elements = &ccache_element,
+ .count = 1,
+ };
+
+ gss_OID_set mech_set = GSS_C_NO_OID_SET;
+ gss_cred_usage_t cred_usage = GSS_C_INITIATE;
+ gss_name_t name = NULL;
+ gss_buffer_desc pr_name = {
+ .value = NULL,
+ .length = 0,
+ };
+
+ if (id != NULL) {
+ major_status = krb5_cc_get_full_name(ctx,
+ id,
+ discard_const(&ccache_element.value));
+ if (major_status != 0) {
+ return major_status;
+ }
+ }
+
+ if (keytab != NULL) {
+ keytab_element.value = malloc(4096);
+ if (!keytab_element.value) {
+ return ENOMEM;
+ }
+ major_status = krb5_kt_get_name(ctx,
+ keytab,
+ discard_const(keytab_element.value), 4096);
+ if (major_status != 0) {
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ cred_usage = GSS_C_ACCEPT;
+ cred_store.elements = &keytab_element;
+
+ if (keytab_principal != NULL) {
+ major_status = krb5_unparse_name(ctx, keytab_principal, (char**)&pr_name.value);
+ if (major_status != 0) {
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ pr_name.length = strlen(pr_name.value);
+
+ major_status = gss_import_name(minor_status,
+ &pr_name,
+ discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
+ &name);
+ if (major_status != 0) {
+ krb5_free_unparsed_name(ctx, pr_name.value);
+ free(discard_const(keytab_element.value));
+ return major_status;
+ }
+ }
+ }
+
+ if (id != NULL && keytab != NULL) {
+ elements[0] = ccache_element;
+ elements[1] = keytab_element;
+
+ cred_store.elements = elements;
+ cred_store.count = 2;
+ cred_usage = GSS_C_BOTH;
+ }
+
+ major_status = gss_acquire_cred_from(minor_status,
+ name,
+ 0,
+ mech_set,
+ cred_usage,
+ &cred_store,
+ cred,
+ NULL,
+ NULL);
+
+ if (pr_name.value != NULL) {
+ (void)gss_release_name(&minor, &name);
+ krb5_free_unparsed_name(ctx, pr_name.value);
+ }
+ if (keytab_element.value != NULL) {
+ free(discard_const(keytab_element.value));
+ }
+ krb5_free_string(ctx, discard_const(ccache_element.value));
+#else
+ major_status = gss_krb5_import_cred(minor_status,
+ id,
+ keytab_principal,
+ keytab, cred);
+#endif
+ return major_status;
+}
+
+
#endif /* HAVE_GSSAPI */
diff --git a/lib/krb5_wrap/gss_samba.h b/lib/krb5_wrap/gss_samba.h
index 5319932..89aee34 100644
--- a/lib/krb5_wrap/gss_samba.h
+++ b/lib/krb5_wrap/gss_samba.h
@@ -25,6 +25,7 @@
#ifdef HAVE_GSSAPI
#include "system/gssapi.h"
+#include "krb5_samba.h"
#if defined(HAVE_GSS_OID_EQUAL)
#define smb_gss_oid_equal gss_oid_equal
@@ -32,5 +33,17 @@
int smb_gss_oid_equal(const gss_OID first_oid, const gss_OID second_oid);
#endif /* HAVE_GSS_OID_EQUAL */
+/* wrapper around gss_krb5_import_cred() that prefers to use gss_acquire_cred_from()
+ * if this GSSAPI extension is available. gss_acquire_cred_from() is properly
+ * interposed by GSS-proxy while gss_krb5_import_cred() is not.
+ *
+ * This wrapper requires a proper krb5_context to resolve the ccache name for
+ * gss_acquire_cred_from().
+ *
+ * All gss_krb5_import_cred() callers in Samba already have krb5_context available. */
+uint32_t smb_gss_krb5_import_cred(OM_uint32 *minor_status, krb5_context ctx,
+ krb5_ccache id, krb5_principal keytab_principal,
+ krb5_keytab keytab, gss_cred_id_t *cred);
+
#endif /* HAVE_GSSAPI */
#endif /* _GSS_SAMBA_H */
--
2.9.3
>From 85487747c1f177af3d0e6f17fa76c7a36ab6f51b Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:57:13 +0200
Subject: [PATCH 3/6] credentials_krb5: convert to use smb_gss_krb5_import_cred
---
auth/credentials/credentials_krb5.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c
index e974df9..0e68012 100644
--- a/auth/credentials/credentials_krb5.c
+++ b/auth/credentials/credentials_krb5.c
@@ -579,8 +579,9 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
return ENOMEM;
}
- maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
+ ccache->ccache, NULL, NULL,
+ &gcc->creds);
if ((maj_stat == GSS_S_FAILURE) &&
(min_stat == (OM_uint32)KRB5_CC_END ||
min_stat == (OM_uint32)KRB5_CC_NOTFOUND ||
@@ -597,8 +598,9 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
return ret;
}
- maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
+ ccache->ccache, NULL, NULL,
+ &gcc->creds);
}
@@ -609,7 +611,7 @@ _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
} else {
ret = EINVAL;
}
- (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret));
+ (*error_string) = talloc_asprintf(cred, "smb_gss_krb5_import_cred failed: %s", error_message(ret));
return ret;
}
@@ -1076,12 +1078,14 @@ _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
if (ktc->password_based || obtained < CRED_SPECIFIED) {
/* This creates a GSSAPI cred_id_t for match-by-key with only the keytab set */
- maj_stat = gss_krb5_import_cred(&min_stat, NULL, NULL, ktc->keytab,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, smb_krb5_context->krb5_context,
+ NULL, NULL, ktc->keytab,
+ &gcc->creds);
} else {
/* This creates a GSSAPI cred_id_t with the principal and keytab set, matching by name */
- maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab,
- &gcc->creds);
+ maj_stat = smb_gss_krb5_import_cred(&min_stat, smb_krb5_context->krb5_context,
+ NULL, princ, ktc->keytab,
+ &gcc->creds);
}
if (maj_stat) {
if (min_stat) {
--
2.9.3
>From 024cbfd7da492d2f4259cc99c7ab62799a311070 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:57:50 +0200
Subject: [PATCH 4/6] libads: convert to use smb_gss_krb5_import_cred
---
source3/libads/sasl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 8570788..30127fa 100644
--- a/source3/libads/sasl.c
+++ b/source3/libads/sasl.c
@@ -372,7 +372,7 @@ static ADS_STATUS ads_init_gssapi_cred(ADS_STRUCT *ads, gss_cred_id_t *cred)
goto done;
}
- maj = gss_krb5_import_cred(&min, kccache, NULL, NULL, cred);
+ maj = smb_gss_krb5_import_cred(&min, kctx, kccache, NULL, NULL, cred);
if (maj != GSS_S_COMPLETE) {
status = ADS_ERROR_GSS(maj, min);
goto done;
--
2.9.3
>From e396848ceee1ff3ad00bdcfd18a56e7345c1d283 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Fri, 3 Mar 2017 16:58:14 +0200
Subject: [PATCH 5/6] s3-gse: convert to use smb_gss_krb5_import_cred
---
source3/librpc/crypto/gse.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index abf20bc..f4238f3 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -252,11 +252,12 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
/* TODO: get krb5 ticket using username/password, if no valid
* one already available in ccache */
- gss_maj = gss_krb5_import_cred(&gss_min,
- gse_ctx->ccache,
- NULL, /* keytab_principal */
- NULL, /* keytab */
- &gse_ctx->creds);
+ gss_maj = smb_gss_krb5_import_cred(&gss_min,
+ gse_ctx->k5ctx,
+ gse_ctx->ccache,
+ NULL, /* keytab_principal */
+ NULL, /* keytab */
+ &gse_ctx->creds);
if (gss_maj) {
char *ccache = NULL;
int kret;
@@ -268,7 +269,7 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
ccache = NULL;
}
- DEBUG(5, ("gss_krb5_import_cred ccache[%s] failed with [%s] -"
+ DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -"
"the caller may retry after a kinit.\n",
ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
SAFE_FREE(ccache);
@@ -430,12 +431,13 @@ static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
}
/* This creates a GSSAPI cred_id_t with the keytab set */
- gss_maj = gss_krb5_import_cred(&gss_min, NULL, NULL, gse_ctx->keytab,
- &gse_ctx->creds);
+ gss_maj = smb_gss_krb5_import_cred(&gss_min, gse_ctx->k5ctx,
+ NULL, NULL, gse_ctx->keytab,
+ &gse_ctx->creds);
if (gss_maj != 0
&& gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
- DEBUG(0, ("gss_krb5_import_cred failed with [%s]\n",
+ DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
gse_errstr(gse_ctx, gss_maj, gss_min)));
status = NT_STATUS_INTERNAL_ERROR;
goto done;
--
2.9.3
>From e7fc9d3c8f2a3a814c58bee60bd326eca013bda4 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <ab at samba.org>
Date: Wed, 8 Mar 2017 12:38:49 +0200
Subject: [PATCH 6/6] s3-gse: move krb5 fallback to smb_gss_krb5_import_cred
wrapper
MIT krb5 1.9 version of gss_krb5_import_cred() may fail when importing
credentials from a keytab without specifying actual principal.
This was fixed in MIT krb5 1.9.2 (see commit
71c3be093db577aa52f6b9a9a3a9f442ca0d8f20 in MIT krb5-1.9 branch, git
master's version is bd18687a705a8a6cdcb7c140764d1a7c6a3381b5).
Move fallback code to the smb_gss_krb5_import_cred wrapper. We only
expect this fallback to happen with krb5 GSSAPI mechanism, thus hard
code use of krb5 mech when calling to gss_acquire_cred.
---
lib/krb5_wrap/gss_samba.c | 46 +++++++++++++++++++++++++++++++++++++++---
source3/librpc/crypto/gse.c | 49 +--------------------------------------------
2 files changed, 44 insertions(+), 51 deletions(-)
diff --git a/lib/krb5_wrap/gss_samba.c b/lib/krb5_wrap/gss_samba.c
index 757ffc5..9e5ad4a 100644
--- a/lib/krb5_wrap/gss_samba.c
+++ b/lib/krb5_wrap/gss_samba.c
@@ -161,9 +161,49 @@ uint32_t smb_gss_krb5_import_cred(uint32_t *minor_status, krb5_context ctx,
krb5_free_string(ctx, discard_const(ccache_element.value));
#else
major_status = gss_krb5_import_cred(minor_status,
- id,
- keytab_principal,
- keytab, cred);
+ id,
+ keytab_principal,
+ keytab, cred);
+
+ if (major_status == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
+ if ((keytab_principal == NULL) && (keytab != NULL)) {
+ /* No principal was specified and MIT krb5 1.9 version failed.
+ * We have to fall back to set global acceptor identity */
+ gss_OID_set_desc mech_set;
+ char *kt_name = NULL;
+
+ kt_name = malloc(4096);
+ if (!kt_name) {
+ return ENOMEM;
+ }
+
+ major_status = krb5_kt_get_name(ctx,
+ keytab,
+ kt_name, 4096);
+ if (major_status != 0) {
+ free(kt_name);
+ return major_status;
+ }
+
+ major_status = gsskrb5_register_acceptor_identity(kt_name);
+ if (major_status) {
+ free(kt_name);
+ return major_status;
+ }
+
+ /* We are dealing with krb5 GSSAPI mech in this fallback */
+ mech_set.count = 1;
+ mech_set.elements = gss_mech_krb5;
+ major_status = gss_acquire_cred(minor_status,
+ GSS_C_NO_NAME,
+ GSS_C_INDEFINITE,
+ &mech_set,
+ GSS_C_ACCEPT,
+ cred,
+ NULL, NULL);
+ free(kt_name);
+ }
+ }
#endif
return major_status;
}
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index f4238f3..a111320 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -435,58 +435,11 @@ static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
NULL, NULL, gse_ctx->keytab,
&gse_ctx->creds);
- if (gss_maj != 0
- && gss_maj != (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME)) {
+ if (gss_maj != 0) {
DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n",
gse_errstr(gse_ctx, gss_maj, gss_min)));
status = NT_STATUS_INTERNAL_ERROR;
goto done;
-
- /* This is the error the MIT krb5 1.9 gives when it
- * implements the function, but we do not specify the
- * principal. However, when we specify the principal
- * as host$@REALM the GSS acceptor fails with 'wrong
- * principal in request'. Work around the issue by
- * falling back to the alternate approach below. */
- } else if (gss_maj == (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME))
- /* FIXME!!!
- * This call sets the default keytab for the whole server, not
- * just for this context. Need to find a way that does not alter
- * the state of the whole server ... */
- {
- const char *ktname;
- gss_OID_set_desc mech_set;
-
- ret = smb_krb5_kt_get_name(gse_ctx, gse_ctx->k5ctx,
- gse_ctx->keytab, &ktname);
- if (ret) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
-
- ret = gsskrb5_register_acceptor_identity(ktname);
- if (ret) {
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
-
- mech_set.count = 1;
- mech_set.elements = &gse_ctx->gss_mech;
-
- gss_maj = gss_acquire_cred(&gss_min,
- GSS_C_NO_NAME,
- GSS_C_INDEFINITE,
- &mech_set,
- GSS_C_ACCEPT,
- &gse_ctx->creds,
- NULL, NULL);
-
- if (gss_maj) {
- DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
- gse_errstr(gse_ctx, gss_maj, gss_min)));
- status = NT_STATUS_INTERNAL_ERROR;
- goto done;
- }
}
status = NT_STATUS_OK;
--
2.9.3
More information about the samba-technical
mailing list