s3:librpc/gse: make use of gss_krb5_import_cred() instead of gss_acquire_cred()
authorStefan Metzmacher <metze@samba.org>
Thu, 22 Dec 2016 07:49:38 +0000 (08:49 +0100)
committerVolker Lendecke <vl@samba.org>
Mon, 2 Jan 2017 17:04:13 +0000 (18:04 +0100)
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@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
source3/librpc/crypto/gse.c

index 1c812f8ad4803e6adbb90b75d74135dc984f7a52..792700ede04c6f361f6882f25d42457c4784b545 100644 (file)
@@ -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;
        }