s3-gse: move krb5 fallback to smb_gss_krb5_import_cred wrapper
authorAlexander Bokovoy <ab@samba.org>
Wed, 8 Mar 2017 10:38:49 +0000 (12:38 +0200)
committerAlexander Bokovoy <ab@samba.org>
Wed, 8 Mar 2017 21:00:24 +0000 (22:00 +0100)
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.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12611

Signed-off-by: Alexander Bokovoy <ab@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Alexander Bokovoy <ab@samba.org>
Autobuild-Date(master): Wed Mar  8 22:00:24 CET 2017 on sn-devel-144

lib/krb5_wrap/gss_samba.c
source3/librpc/crypto/gse.c

index 757ffc5a33ebb802045a62ef362664c10c2a240c..9e5ad4a3c8eb0a0fb0e81a4e3fa583197cf8910d 100644 (file)
@@ -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;
 }
index f4238f32441b3f3b225c19eb08b2cae9ac88c684..a111320e829eb8221ceee0a079471e88b44a551c 100644 (file)
@@ -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;