lib/krb5_wrap: add smb_gss_krb5_import_cred wrapper
authorAlexander Bokovoy <ab@samba.org>
Fri, 3 Mar 2017 14:14:57 +0000 (16:14 +0200)
committerAlexander Bokovoy <ab@samba.org>
Wed, 8 Mar 2017 17:00:11 +0000 (18:00 +0100)
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.

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>
lib/krb5_wrap/gss_samba.c
lib/krb5_wrap/gss_samba.h

index b444633e280ee84333ce2d95aec88fe07e77c156..757ffc5a33ebb802045a62ef362664c10c2a240c 100644 (file)
@@ -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 */
index 531993263bb31316580f65760d79a91c993e041a..89aee3479c550ccfff0a13bd993e4d0f77a6e546 100644 (file)
@@ -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
 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 */