krb5 commit: Implement credential store support for krb5 mech

Greg Hudson ghudson at MIT.EDU
Fri Jul 20 15:36:30 EDT 2012


https://github.com/krb5/krb5/commit/721f9565de4f5ae4c13e152218d5261c0cdbb620
commit 721f9565de4f5ae4c13e152218d5261c0cdbb620
Author: Simo Sorce <simo at redhat.com>
Date:   Fri Mar 2 23:11:32 2012 -0500

    Implement credential store support for krb5 mech

 src/lib/gssapi/krb5/Makefile.in    |    3 +
 src/lib/gssapi/krb5/acquire_cred.c |  125 +++++++++++++++++++++++++++++++----
 src/lib/gssapi/krb5/cred_store.c   |   50 ++++++++++++++
 src/lib/gssapi/krb5/gssapiP_krb5.h |   34 ++++++++++
 src/lib/gssapi/krb5/gssapi_krb5.c  |    2 +
 src/lib/gssapi/krb5/store_cred.c   |   76 ++++++++++++++++++----
 6 files changed, 263 insertions(+), 27 deletions(-)

diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in
index 5998fc0..ddd9ef9 100644
--- a/src/lib/gssapi/krb5/Makefile.in
+++ b/src/lib/gssapi/krb5/Makefile.in
@@ -43,6 +43,7 @@ SRCS = \
 	$(srcdir)/compare_name.c \
 	$(srcdir)/context_time.c \
 	$(srcdir)/copy_ccache.c \
+	$(srcdir)/cred_store.c \
 	$(srcdir)/delete_sec_context.c \
 	$(srcdir)/disp_name.c \
 	$(srcdir)/disp_status.c \
@@ -93,6 +94,7 @@ OBJS = \
 	$(OUTPRE)compare_name.$(OBJEXT) \
 	$(OUTPRE)context_time.$(OBJEXT) \
 	$(OUTPRE)copy_ccache.$(OBJEXT) \
+	$(OUTPRE)cred_store.$(OBJEXT) \
 	$(OUTPRE)delete_sec_context.$(OBJEXT) \
 	$(OUTPRE)disp_name.$(OBJEXT) \
 	$(OUTPRE)disp_status.$(OBJEXT) \
@@ -146,6 +148,7 @@ STLIBOBJS = \
 	compare_name.o \
 	context_time.o \
 	copy_ccache.o \
+	cred_store.o \
 	delete_sec_context.o \
 	disp_name.o \
 	disp_status.o \
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
index 0527d13..258ec74 100644
--- a/src/lib/gssapi/krb5/acquire_cred.c
+++ b/src/lib/gssapi/krb5/acquire_cred.c
@@ -716,13 +716,13 @@ error:
 }
 
 static OM_uint32
-acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
-             gss_buffer_t password, OM_uint32 time_req,
-             gss_cred_usage_t cred_usage, krb5_ccache ccache,
-             krb5_keytab keytab, krb5_boolean iakerb,
-             gss_cred_id_t *output_cred_handle, OM_uint32 *time_rec)
+acquire_cred_context(krb5_context context, OM_uint32 *minor_status,
+                     gss_name_t desired_name, gss_buffer_t password,
+                     OM_uint32 time_req, gss_cred_usage_t cred_usage,
+                     krb5_ccache ccache, krb5_keytab keytab,
+                     krb5_boolean iakerb, gss_cred_id_t *output_cred_handle,
+                     OM_uint32 *time_rec)
 {
-    krb5_context context = NULL;
     krb5_gss_cred_id_t cred = NULL;
     krb5_gss_name_t name = (krb5_gss_name_t)desired_name;
     OM_uint32 ret;
@@ -733,14 +733,6 @@ acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
     if (time_rec)
         *time_rec = 0;
 
-    code = gss_krb5int_initialize_library();
-    if (code)
-        goto krb_error_out;
-
-    code = krb5_gss_init_context(&context);
-    if (code)
-        goto krb_error_out;
-
     /* create the gss cred structure */
     cred = k5alloc(sizeof(krb5_gss_cred_id_rec), &code);
     if (cred == NULL)
@@ -821,7 +813,6 @@ acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
     *minor_status = 0;
     *output_cred_handle = (gss_cred_id_t) cred;
 
-    krb5_free_context(context);
     return GSS_S_COMPLETE;
 
 krb_error_out:
@@ -844,6 +835,39 @@ error_out:
         xfree(cred);
     }
     save_error_info(*minor_status, context);
+    return ret;
+}
+
+static OM_uint32
+acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
+             gss_buffer_t password, OM_uint32 time_req,
+             gss_cred_usage_t cred_usage, krb5_ccache ccache,
+             krb5_keytab keytab, krb5_boolean iakerb,
+             gss_cred_id_t *output_cred_handle, OM_uint32 *time_rec)
+{
+    krb5_context context = NULL;
+    krb5_error_code code = 0;
+    OM_uint32 ret;
+
+    code = gss_krb5int_initialize_library();
+    if (code) {
+        *minor_status = code;
+        ret = GSS_S_FAILURE;
+        goto out;
+    }
+
+    code = krb5_gss_init_context(&context);
+    if (code) {
+        *minor_status = code;
+        ret = GSS_S_FAILURE;
+        goto out;
+    }
+
+    ret = acquire_cred_context(context, minor_status, desired_name, password,
+                               time_req, cred_usage, ccache, keytab, iakerb,
+                               output_cred_handle, time_rec);
+
+out:
     krb5_free_context(context);
     return ret;
 }
@@ -1092,3 +1116,74 @@ gss_krb5int_import_cred(OM_uint32 *minor_status,
         k5_mutex_destroy(&name.lock);
     return code;
 }
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_from(OM_uint32 *minor_status,
+                           const gss_name_t desired_name,
+                           OM_uint32 time_req,
+                           const 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,
+                           OM_uint32 *time_rec)
+{
+    krb5_context context = NULL;
+    krb5_error_code code = 0;
+    krb5_keytab keytab = NULL;
+    krb5_ccache ccache = NULL;
+    const char *value;
+    OM_uint32 ret;
+
+    code = gss_krb5int_initialize_library();
+    if (code) {
+        *minor_status = code;
+        ret = GSS_S_FAILURE;
+        goto out;
+    }
+
+    code = krb5_gss_init_context(&context);
+    if (code) {
+        *minor_status = code;
+        ret = GSS_S_FAILURE;
+        goto out;
+    }
+
+    ret = kg_value_from_cred_store(cred_store, KRB5_CS_CCACHE_URN, &value);
+    if (GSS_ERROR(ret))
+        goto out;
+
+    if (value) {
+        code = krb5_cc_resolve(context, value, &ccache);
+        if (code != 0) {
+            *minor_status = code;
+            ret = GSS_S_CRED_UNAVAIL;
+            goto out;
+        }
+    }
+
+    ret = kg_value_from_cred_store(cred_store, KRB5_CS_KEYTAB_URN, &value);
+    if (GSS_ERROR(ret))
+        goto out;
+
+    if (value) {
+        code = krb5_kt_resolve(context, value, &keytab);
+        if (code != 0) {
+            *minor_status = code;
+            ret = GSS_S_CRED_UNAVAIL;
+            goto out;
+        }
+    }
+
+    ret = acquire_cred_context(context, minor_status, desired_name, NULL,
+                               time_req, cred_usage, ccache, keytab, 0,
+                               output_cred_handle, time_rec);
+
+out:
+    if (ccache != NULL)
+        krb5_cc_close(context, ccache);
+    if (keytab != NULL)
+        krb5_kt_close(context, keytab);
+    krb5_free_context(context);
+    return ret;
+}
diff --git a/src/lib/gssapi/krb5/cred_store.c b/src/lib/gssapi/krb5/cred_store.c
new file mode 100644
index 0000000..008dd20
--- /dev/null
+++ b/src/lib/gssapi/krb5/cred_store.c
@@ -0,0 +1,50 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "gssapiP_krb5.h"
+
+OM_uint32
+kg_value_from_cred_store(gss_const_key_value_set_t cred_store,
+                         const char *type, const char **value)
+{
+    OM_uint32 i;
+
+    if (value == NULL)
+        return GSS_S_CALL_INACCESSIBLE_WRITE;
+    *value = NULL;
+
+    if (cred_store == GSS_C_NO_CRED_STORE)
+        return GSS_S_COMPLETE;
+
+    for (i = 0; i < cred_store->count; i++) {
+        if (strcmp(cred_store->elements[i].key, type) == 0) {
+            if (*value != NULL)
+                return GSS_S_DUPLICATE_ELEMENT;
+            *value = cred_store->elements[i].value;
+        }
+    }
+
+    return GSS_S_COMPLETE;
+}
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 9b0d6cc..56b025b 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -1224,4 +1224,38 @@ data_to_gss(krb5_data *input_k5data, gss_buffer_t output_buffer)
 
 #define KRB5_GSS_EXTS_IAKERB_FINISHED 1
 
+
+/* Credential store extensions */
+
+#define KRB5_CS_KEYTAB_URN "keytab"
+#define KRB5_CS_CCACHE_URN "ccache"
+
+OM_uint32
+kg_value_from_cred_store(gss_const_key_value_set_t cred_store,
+                         const char *type, const char **value);
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_acquire_cred_from(
+    OM_uint32 *,               /* minor_status */
+    const gss_name_t,          /* desired_name */
+    OM_uint32,                 /* time_req */
+    const 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 */
+    OM_uint32 *);              /* time_rec */
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred_into(
+    OM_uint32 *,               /* minor_status */
+    gss_cred_id_t,             /* input_cred_handle */
+    gss_cred_usage_t,          /* input_usage */
+    const gss_OID,             /* desired_mech */
+    OM_uint32,                 /* overwrite_cred */
+    OM_uint32,                 /* default_cred */
+    gss_const_key_value_set_t, /* cred_store */
+    gss_OID_set *,             /* elements_stored */
+    gss_cred_usage_t *);       /* cred_usage_stored */
+
 #endif /* _GSSAPIP_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 068af43..e94b90c 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -897,6 +897,8 @@ static struct gss_config krb5_mechanism = {
     krb5_gss_inquire_saslname_for_mech,
     krb5_gss_inquire_mech_for_saslname,
     krb5_gss_inquire_attrs_for_mech,
+    krb5_gss_acquire_cred_from,
+    krb5_gss_store_cred_into,
 };
 
 static struct gss_config_ext krb5_mechanism_ext = {
diff --git a/src/lib/gssapi/krb5/store_cred.c b/src/lib/gssapi/krb5/store_cred.c
index d587589..0a020d7 100644
--- a/src/lib/gssapi/krb5/store_cred.c
+++ b/src/lib/gssapi/krb5/store_cred.c
@@ -32,7 +32,8 @@
 static int
 has_unexpired_creds(krb5_gss_cred_id_t kcred,
                     const gss_OID desired_mech,
-                    int default_cred)
+                    int default_cred,
+                    gss_const_key_value_set_t cred_store)
 {
     OM_uint32 major_status, minor;
     gss_name_t cred_name;
@@ -48,9 +49,10 @@ has_unexpired_creds(krb5_gss_cred_id_t kcred,
     else
         cred_name = (gss_name_t)kcred->name;
 
-    major_status = krb5_gss_acquire_cred(&minor, cred_name, 0,
-                                         &desired_mechs, GSS_C_INITIATE,
-                                         &tmp_cred, NULL, &time_rec);
+    major_status = krb5_gss_acquire_cred_from(&minor, cred_name, 0,
+                                              &desired_mechs, GSS_C_INITIATE,
+                                              cred_store, &tmp_cred, NULL,
+                                              &time_rec);
 
     krb5_gss_release_cred(&minor, &tmp_cred);
 
@@ -62,15 +64,19 @@ copy_initiator_creds(OM_uint32 *minor_status,
                      gss_cred_id_t input_cred_handle,
                      const gss_OID desired_mech,
                      OM_uint32 overwrite_cred,
-                     OM_uint32 default_cred)
+                     OM_uint32 default_cred,
+                     gss_const_key_value_set_t cred_store)
 {
     OM_uint32 major_status;
     krb5_error_code code;
     krb5_gss_cred_id_t kcred = NULL;
     krb5_context context = NULL;
     krb5_ccache ccache = NULL;
+    const char *ccache_name;
 
-    if (!default_cred) {
+    *minor_status = 0;
+
+    if (!default_cred && cred_store == GSS_C_NO_CRED_STORE) {
         *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
         major_status = GSS_S_FAILURE;
         goto cleanup;
@@ -98,16 +104,44 @@ copy_initiator_creds(OM_uint32 *minor_status,
     }
 
     if (!overwrite_cred &&
-        has_unexpired_creds(kcred, desired_mech, default_cred)) {
+        has_unexpired_creds(kcred, desired_mech, default_cred, cred_store)) {
         major_status = GSS_S_DUPLICATE_ELEMENT;
         goto cleanup;
     }
 
-    code = krb5int_cc_default(context, &ccache);
-    if (code != 0) {
-        *minor_status = code;
-        major_status = GSS_S_FAILURE;
+    major_status = kg_value_from_cred_store(cred_store,
+                                            KRB5_CS_CCACHE_URN, &ccache_name);
+    if (GSS_ERROR(major_status))
         goto cleanup;
+
+    if (ccache_name != NULL) {
+        code = krb5_cc_resolve(context, ccache_name, &ccache);
+        if (code != 0) {
+            *minor_status = code;
+            major_status = GSS_S_CRED_UNAVAIL;
+            goto cleanup;
+        }
+        code = krb5_cc_initialize(context, ccache,
+                                  kcred->name->princ);
+        if (code != 0) {
+            *minor_status = code;
+            major_status = GSS_S_CRED_UNAVAIL;
+            goto cleanup;
+        }
+    }
+
+    if (ccache == NULL) {
+        if (!default_cred) {
+            *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
+            major_status = GSS_S_FAILURE;
+            goto cleanup;
+        }
+        code = krb5int_cc_default(context, &ccache);
+        if (code != 0) {
+            *minor_status = code;
+            major_status = GSS_S_FAILURE;
+            goto cleanup;
+        }
     }
 
     code = krb5_cc_copy_creds(context, kcred->ccache, ccache);
@@ -140,6 +174,24 @@ krb5_gss_store_cred(OM_uint32 *minor_status,
                     gss_OID_set *elements_stored,
                     gss_cred_usage_t *cred_usage_stored)
 {
+    return krb5_gss_store_cred_into(minor_status, input_cred_handle,
+                                    cred_usage, desired_mech,
+                                    overwrite_cred, default_cred,
+                                    GSS_C_NO_CRED_STORE,
+                                    elements_stored, cred_usage_stored);
+}
+
+OM_uint32 KRB5_CALLCONV
+krb5_gss_store_cred_into(OM_uint32 *minor_status,
+                         gss_cred_id_t input_cred_handle,
+                         gss_cred_usage_t cred_usage,
+                         const gss_OID desired_mech,
+                         OM_uint32 overwrite_cred,
+                         OM_uint32 default_cred,
+                         gss_const_key_value_set_t cred_store,
+                         gss_OID_set *elements_stored,
+                         gss_cred_usage_t *cred_usage_stored)
+{
     OM_uint32 major_status;
     gss_cred_usage_t actual_usage;
     OM_uint32 lifetime;
@@ -173,7 +225,7 @@ krb5_gss_store_cred(OM_uint32 *minor_status,
 
     major_status = copy_initiator_creds(minor_status, input_cred_handle,
                                         desired_mech, overwrite_cred,
-                                        default_cred);
+                                        default_cred, cred_store);
     if (GSS_ERROR(major_status))
         return major_status;
 


More information about the cvs-krb5 mailing list