Require MIT 1.10? (Re: credentials_krb5: use gss_acquire_cred for client-side GSSAPI use case)

Alexander Bokovoy ab at samba.org
Tue Mar 7 11:45:34 UTC 2017


On ma, 06 maalis 2017, Alexander Bokovoy wrote:
> On ma, 06 maalis 2017, Stefan Metzmacher wrote:
> > Am 06.03.2017 um 15:58 schrieb Alexander Bokovoy:
> > > On ma, 06 maalis 2017, Stefan Metzmacher wrote:
> > >> Am 06.03.2017 um 15:45 schrieb Alexander Bokovoy:
> > >>> On ma, 06 maalis 2017, Stefan Metzmacher wrote:
> > >>>> Am 06.03.2017 um 12:16 schrieb Alexander Bokovoy:
> > >>>>> On ma, 06 maalis 2017, Stefan Metzmacher wrote:
> > >>>>>> Hi Alexander,
> > >>>>>>
> > >>>>>>>>> ACK. Will do that.
> > >>>>>>>> I pushed current patchset to
> > >>>>>>>> https://git.samba.org/?p=ab/samba.git/.git;a=shortlog;h=refs/heads/master-gss_acquire_cred_from
> > >>>>>>>>
> > >>>>>>>> I'm running tests right now. Will submit final patch once they pass.
> > >>>>>>> Final patch is attached.
> > >>>>>>
> > >>>>>> I think we should also handle the keytab_principal argument
> > >>>>>> (or drop it from the argument list of the wrapper).
> > >>>>> This is done (attached). There is a need to use keytab_principal as it
> > >>>>> is passed by the credentials code.
> > >>>>>  
> > >>>>>> And please also add the fallback logic for broken
> > >>>>>> of gse_init_server() to handle the broken gss_krb5_import_cred()
> > >>>>>> for the acceptor into the wrapper. And/or reseach if the fallback
> > >>>>>> logic is still needed with our requirement for MIT 1.9.
> > >>>>> For the latter, 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&section=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=
> > >>>>>
> > >>>>> I think we can relatively safely drop MIT 1.9 and move to MIT 1.10 as a
> > >>>>> requirement. RHEL 5 stuck with 1.6 anyway.
> > >>>>
> > >>>> I'm fine to move to MIT 1.10, but I guess better only for master/4.7.
> > >>> Yes.
> > >>>  
> > >>>> If you want this backported to 4.6:
> > >>>> - please at the fallback to the wrapper first
> > >>>> - then change the configure check to require 1.10
> > >>>> - remove the fallback
> > >>>>
> > >>>> If you don't need a backport:
> > >>>> - change the configure check to require 1.10
> > >>>> - remove the fallback
> > >>>> - apply your current patches
> > >>> I don't need a fallback in the backported code, actually, because the
> > >>> oldest release I need to backport already has 1.10.
> > >>
> > >> So you'll keep the backport only in the RHEL packages?
> > > I mean, environments where I need Samba 4.6 with this patch all have MIT
> > > Krb5 >= 1.14 so introducing configure check and keeping fallback there
> > > is not needed.
> > 
> > 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

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().
On Heimdal they would eventually end up with gss_krb5_import_cred(), as
before.

For FreeIPA 4.5 I can leave with auth/credentials/credentials_krb5.c
using smb_gss_krb5_import_cred() interface. I'm going to rework
ccache handle-based interface in credentials later to maintain a
cred_store with ccache/keytab references. Andreas already has partially
done this.

Patchsets for git master and v4.6 are attached.

-- 
/ Alexander Bokovoy
-------------- next part --------------
>From f77bc5a83def4d0cfa59e455394461addbb800ed 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 06c1d3286bafffb7152da7f02e00dffb8d6c64b9 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 fd1915cd0e7d0e31bd6feee7e6ecbcbf95052f46 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 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 782aa72ec104ccfc77d2d31a65f0c50fd8f65db5 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 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 126cfb5c1dc8e9ca322a092225c998da62a3f25d 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 99971d3..565afc8 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);
@@ -396,12 +397,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 f45a1a571fb7cc801545efc873ca7527765ce351 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 cbdd58079729e7c87b11c3a19557af28ef39c496 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 b27c974d7a624eb1c981e01c0fee03307421ebc5 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 ea0eac71d11b33a8448f75798d82b16d6657fe7b 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 565afc8..b6adf6b 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -382,6 +382,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);
@@ -396,66 +405,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 d3e50f0756f9007698eab28908d8f82a8db5ac9f 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&section=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 eb4ce9cd3780e8558bdc378ae55b22bb68571978 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 b6adf6b..039a916 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -418,32 +418,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 dbd9d6ce018cab11de9ea77f9959f4631b2d6c41 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 039a916..cf21b89 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 4c7dbaa98f2209c9b98b18bee6caa8830dc85c73 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 | 69 +++++++++++++++------------------------------------
 1 file changed, 20 insertions(+), 49 deletions(-)

diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c
index 30127fa..d7792ec 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,57 +365,23 @@ 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);
-	}
-
-#ifdef HAVE_GSS_KRB5_IMPORT_CRED
-	kerr = krb5_cc_resolve(kctx, ads->auth.ccache_name, &kccache);
-	if (kerr) {
-		status = ADS_ERROR_KRB5(kerr);
-		goto done;
-	}
+	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;
 
-	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;
 	}
-#else
-	/* We need to fallback to overriding the default creds.
-	 * This operation is not thread safe as it changes the process
-	 * environment variable, but we do not have any better option
-	 * with older kerberos libraries */
-	{
-		const char *oldccname = NULL;
-
-		oldccname = getenv("KRB5CCNAME");
-		setenv("KRB5CCNAME", ads->auth.ccache_name, 1);
-
-		maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
-				       NULL, GSS_C_INITIATE, cred, NULL, NULL);
 
-		if (oldccname) {
-			setenv("KRB5CCNAME", oldccname, 1);
-		} else {
-			unsetenv("KRB5CCNAME");
-		}
-
-		if (maj != GSS_S_COMPLETE) {
-			status = ADS_ERROR_GSS(maj, min);
-			goto done;
-		}
-	}
-#endif
-
-	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 cc2f5e81a63fe43174bf1680741e2ec6e340bec7 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 b12cee21c04340e2733ee20b9fc2b58400fe86fc 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 e28cb67fc6358dbdfb69c64ed4fe2f03b7397309 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 ad1f95c80f0b6dd637bb574bb18b1bb539422c0c 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 5d3927eef30a9e7e2f834522217cebd87569d878 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 b90888bcdff1524ca166df2cdfcf88ccc18ff483 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 7c25d2917db4c664865a42e67d442200feee1508 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 91733192586b0325639ed33c3928e21eff4998a5 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 524c7ab2c9c401a0557b1530c4b3d347555384df 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 715c0cb36338537277ca6a6cf9f58ef8dac56262 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&section=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 9d77b7204d07d182ce8cc22afd799cacdc0dfa23 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 cf5f75080ebcbcf6491db6c57232c7ad915ef320 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 ba59c9c31cf4b5b77e92902f3522fc6a9efb3b98 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



More information about the samba-technical mailing list