[Patches] avoid krb5_ccache ccselect magic (bug #12480)

Alexander Bokovoy ab at samba.org
Thu Dec 29 22:06:11 UTC 2016


On to, 29 joulu 2016, Stefan Metzmacher wrote:
> Hi,
> 
> here're my patches for https://bugzilla.samba.org/show_bug.cgi?id=12480.
> 
> Using gss_acquire_cred() (of MIT krb5) followed by
> gss_init_sec_context() will
> randomly choose any credential cache (from a global list) that
> matches the realm of target principal.
> 
> Have a look at the commit messages or the bug for more details...
> 
> Please review and push:-)
RB+ for first two patches.

> From 69723ac36d31effd5c1949de0ce693d2face7b2c Mon Sep 17 00:00:00 2001
> From: Stefan Metzmacher <metze at samba.org>
> Date: Thu, 22 Dec 2016 08:49:38 +0100
> Subject: [PATCH 3/3] s3:librpc/gse: make use of gss_krb5_import_cred() instead
>  of gss_acquire_cred()
> 
> This avoids the usage of the ccselect_realm logic in MIT krb5,
> which leads to unpredictable results.
> 
> The problem is the usage of gss_acquire_cred(), that just creates
> a credential handle without ccache.
> 
> As result gss_init_sec_context() will trigger a code path
> where it use "ccselect" plugins. And the ccselect_realm
> module just chooses a random ccache from a global list
> where the realm of the provides target principal matches
> the realm of the ccache user principal.
> 
> In the winbindd case we're using MEMORY:cliconnect to setup
> the smb connection to the DC. For ldap connections we use
> MEMORY:winbind_ccache.
> 
> The typical case is that we do the smb connection first.
> If we try to create a new ldap connection, while the
> credentials in MEMORY:cliconnect are expired,
> we'll do the required kinit into MEMORY:winbind_ccache,
> but the ccselect_realm module will select MEMORY:cliconnect
> and tries to get a service ticket for the ldap server
> using the already expired TGT from MEMORY:cliconnect.
> 
> The solution will be to use gss_krb5_import_cred() and explicitly
> pass the desired ccache, which avoids the ccselect logic.
> 
> We could also use gss_acquire_cred_from(), but that's only available
> in modern MIT krb5 versions, while gss_krb5_import_cred() is available
> in heimdal and all supported MIT versions (>=1.9).
> As far as I can see both call the same internal function in MIT
> (at least for the ccache case).
> 
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=12480
> 
> Signed-off-by: Stefan Metzmacher <metze at samba.org>
> Reviewed-by: Andreas Schneider <asn at samba.org>

This is because memory credentials cache in MIT Kerberos implements
collection traversal API and has no way to toggle the behavior to stick
to a single ccache instead of traversing sequentially the whole
collection. I guess this was known to core MIT developers since 2005
when Tom Yu implemented cursor API in the memory ccache backend but
wasn't really realized by external community when MIT Kerberos 1.10
officially added support for credentials collection based on the
collection traversal API. The documentation (doc/basic/ccache_def.rst) 
claims that 
=============
Credential cache collections are new in release 1.10, with support
from the **DIR** and **API** ccache types.  Starting in release 1.12,
collections are also supported by the **KEYRING** ccache type.
Collections are supported by the **KCM** ccache type in release 1.13.
=============

So MEMORY ccache type should not be treated as the collection but it
is. I guess we have to raise this question to the MIT Kerberos
development team and see how can we fix it.

API ccache type is a Windows-only thing.

Until there is a fix in MIT Kerberos for MEMORY ccache type not being
treated as a credentials caches collection, I fear we have to include
this patch.

> ---
>  source3/librpc/crypto/gse.c | 31 ++++++++++++++++++-------------
>  1 file changed, 18 insertions(+), 13 deletions(-)
> 
> diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
> index 1c812f8..792700e 100644
> --- a/source3/librpc/crypto/gse.c
> +++ b/source3/librpc/crypto/gse.c
> @@ -204,7 +204,6 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
>  	struct gse_context *gse_ctx;
>  	OM_uint32 gss_maj, gss_min;
>  	gss_buffer_desc name_buffer = GSS_C_EMPTY_BUFFER;
> -	gss_OID_set_desc mech_set;
>  #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
>  	gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
>  	gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
> @@ -253,20 +252,26 @@ static NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
>  	/* TODO: get krb5 ticket using username/password, if no valid
>  	 * one already available in ccache */
>  
> -	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_INITIATE,
> -				   &gse_ctx->creds,
> -				   NULL, NULL);
> +	gss_maj = gss_krb5_import_cred(&gss_min,
> +				       gse_ctx->ccache,
> +				       NULL, /* keytab_principal */
> +				       NULL, /* keytab */
> +				       &gse_ctx->creds);
>  	if (gss_maj) {
> -		DEBUG(5, ("gss_acquire_creds failed for GSS_C_NO_NAME with [%s] -"
> +		char *ccache = NULL;
> +		int kret;
> +
> +		kret = krb5_cc_get_full_name(gse_ctx->k5ctx,
> +					     gse_ctx->ccache,
> +					     &ccache);
> +		if (kret != 0) {
> +			ccache = NULL;
> +		}
> +
> +		DEBUG(5, ("gss_krb5_import_cred ccache[%s] failed with [%s] -"
>  			  "the caller may retry after a kinit.\n",
> -			  gse_errstr(gse_ctx, gss_maj, gss_min)));
> +			  ccache, gse_errstr(gse_ctx, gss_maj, gss_min)));
> +		SAFE_FREE(ccache);
>  		status = NT_STATUS_INTERNAL_ERROR;
>  		goto err_out;
>  	}
> -- 
> 1.9.1
> 




-- 
/ Alexander Bokovoy



More information about the samba-technical mailing list