krb5 commit: Add OID to inquire GSS cred impersonator name

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/750cd27317d8e8af506c3b9e412a3ccbeef299b0
commit 750cd27317d8e8af506c3b9e412a3ccbeef299b0
Author: Simo Sorce <[email protected]>
Date:   Thu Jan 26 05:45:17 2017 -0500

    Add OID to inquire GSS cred impersonator name
    
    In the krb5 GSS mechanism, add support in gss_inquire_cred_by_oid()
    for inquiring the impersonator name of a credential object, using OID
    1.2.840.113554.1.2.2.5.14.
    
    [[email protected]: edited code slightly; added documentation; expanded
    commit message]
    
    ticket: 8548 (new)

 doc/appdev/gssapi.rst                 |   19 +++++++++++++++
 src/lib/gssapi/krb5/gssapiP_krb5.h    |    6 +++++
 src/lib/gssapi/krb5/gssapi_krb5.c     |   16 ++++++++-----
 src/lib/gssapi/krb5/gssapi_krb5.h     |    9 +++++++
 src/lib/gssapi/krb5/inq_cred.c        |   41 +++++++++++++++++++++++++++++++++
 src/lib/gssapi/libgssapi_krb5.exports |    1 +
 src/tests/gssapi/t_s4u.c              |   20 ++++++++++++++++
 7 files changed, 106 insertions(+), 6 deletions(-)

diff --git a/doc/appdev/gssapi.rst b/doc/appdev/gssapi.rst
index 0258f79..c39bbdd 100644
--- a/doc/appdev/gssapi.rst
+++ b/doc/appdev/gssapi.rst
@@ -312,6 +312,25 @@ issue a ticket from the client to the target service.  The GSSAPI
 library will then use this ticket to authenticate to the target
 service.
 
+If an application needs to find out whether a credential it holds is a
+proxy credential and the name of the intermediate service, it can
+query the credential with the **GSS_KRB5_GET_CRED_IMPERSONATOR** OID
+(new in release 1.16, declared in ``<gssapi/gssapi_krb5.h>``) using
+the gss_inquire_cred_by_oid extension (declared in
+``<gssapi/gssapi_ext.h>``)::
+
+    OM_uint32 gss_inquire_cred_by_oid(OM_uint32 *minor_status,
+                                      const gss_cred_id_t cred_handle,
+                                      gss_OID desired_object,
+                                      gss_buffer_set_t *data_set);
+
+If the call succeeds and *cred_handle* is a proxy credential,
+*data_set* will be set to a single-element buffer set containing the
+unparsed principal name of the intermediate service.  If *cred_handle*
+is not a proxy credential, *data_set* will be set to an empty buffer
+set.  If the library does not support the query,
+gss_inquire_cred_by_oid will return **GSS_S_UNAVAILABLE**.
+
 
 AEAD message wrapping
 ---------------------
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index d7bdef7..cd65966 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -1425,4 +1425,10 @@ iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
  * the format changes. */
 #define CRED_EXPORT_MAGIC "K5C1"
 
+OM_uint32
+gss_krb5int_get_cred_impersonator(OM_uint32 *minor_status,
+                                  const gss_cred_id_t cred_handle,
+                                  const gss_OID desired_object,
+                                  gss_buffer_set_t *data_set);
+
 #endif /* _GSSAPIP_KRB5_H_ */
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 99092cc..e12b662 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -126,6 +126,8 @@
 
 #define NO_CI_FLAGS_X_OID_LENGTH 6
 #define NO_CI_FLAGS_X_OID "\x2a\x85\x70\x2b\x0d\x1d"
+#define GET_CRED_IMPERSONATOR_OID_LENGTH 11
+#define GET_CRED_IMPERSONATOR_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e"
 
 const gss_OID_desc krb5_gss_oid_array[] = {
     /* this is the official, rfc-specified OID */
@@ -148,6 +150,8 @@ const gss_OID_desc krb5_gss_oid_array[] = {
     /* gss_nt_krb5_principal.  Object identifier for a krb5_principal. Do not use. */
     {10, "\052\206\110\206\367\022\001\002\002\002"},
     {NO_CI_FLAGS_X_OID_LENGTH, NO_CI_FLAGS_X_OID},
+    /* this is an inquire cred OID */
+    {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
     { 0, 0 }
 };
 
@@ -164,6 +168,7 @@ const gss_OID gss_nt_krb5_principal             = &kg_oids[6];
 const gss_OID GSS_KRB5_NT_PRINCIPAL_NAME        = &kg_oids[5];
 
 const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X       = &kg_oids[7];
+const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR    = &kg_oids[8];
 
 static const gss_OID_set_desc oidsets[] = {
     {1, &kg_oids[0]}, /* RFC OID */
@@ -400,13 +405,16 @@ krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
 /*
  * gss_inquire_cred_by_oid() methods
  */
-#if 0
+
 static struct {
     gss_OID_desc oid;
     OM_uint32 (*func)(OM_uint32 *, const gss_cred_id_t, const gss_OID, gss_buffer_set_t *);
 } krb5_gss_inquire_cred_by_oid_ops[] = {
+    {
+        {GET_CRED_IMPERSONATOR_OID_LENGTH, GET_CRED_IMPERSONATOR_OID},
+        gss_krb5int_get_cred_impersonator
+    }
 };
-#endif
 
 static OM_uint32 KRB5_CALLCONV
 krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
@@ -415,9 +423,7 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
                              gss_buffer_set_t *data_set)
 {
     OM_uint32 major_status = GSS_S_FAILURE;
-#if 0
     size_t i;
-#endif
 
     if (minor_status == NULL)
         return GSS_S_CALL_INACCESSIBLE_WRITE;
@@ -440,7 +446,6 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
     if (GSS_ERROR(major_status))
         return major_status;
 
-#if 0
     for (i = 0; i < sizeof(krb5_gss_inquire_cred_by_oid_ops)/
              sizeof(krb5_gss_inquire_cred_by_oid_ops[0]); i++) {
         if (g_OID_prefix_equal(desired_object, &krb5_gss_inquire_cred_by_oid_ops[i].oid)) {
@@ -450,7 +455,6 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
                                                                data_set);
         }
     }
-#endif
 
     *minor_status = EINVAL;
 
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h
index 37fa3da..e145eec 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.h
+++ b/src/lib/gssapi/krb5/gssapi_krb5.h
@@ -96,6 +96,15 @@ GSS_DLLIMP extern const gss_OID_desc krb5_gss_oid_array[];
  */
 GSS_DLLIMP extern const gss_OID GSS_KRB5_CRED_NO_CI_FLAGS_X;
 
+/*
+ * This OID can be used with gss_inquire_cred_by_oid(0 to retrieve the
+ * impersonator name (if any).
+ *
+ * iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * krb5(2) krb5-gssapi-ext(5) get-cred-impersonator(14)
+ */
+GSS_DLLIMP extern const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR;
+
 #define gss_krb5_nt_general_name        gss_nt_krb5_name
 #define gss_krb5_nt_principal           gss_nt_krb5_principal
 #define gss_krb5_nt_service_name        gss_nt_service_name
diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c
index 4e35a05..d375f86 100644
--- a/src/lib/gssapi/krb5/inq_cred.c
+++ b/src/lib/gssapi/krb5/inq_cred.c
@@ -245,3 +245,44 @@ krb5_gss_inquire_cred_by_mech(minor_status, cred_handle,
     }
     return(mstat);
 }
+
+OM_uint32
+gss_krb5int_get_cred_impersonator(OM_uint32 *minor_status,
+                                  const gss_cred_id_t cred_handle,
+                                  const gss_OID desired_object,
+                                  gss_buffer_set_t *data_set)
+{
+    krb5_gss_cred_id_t cred = (krb5_gss_cred_id_t)cred_handle;
+    gss_buffer_desc rep = GSS_C_EMPTY_BUFFER;
+    krb5_context context = NULL;
+    char *impersonator = NULL;
+    krb5_error_code ret;
+    OM_uint32 major;
+
+    *data_set = GSS_C_NO_BUFFER_SET;
+
+    /* Return an empty buffer set if no impersonator is present */
+    if (cred->impersonator == NULL)
+        return generic_gss_create_empty_buffer_set(minor_status, data_set);
+
+    ret = krb5_gss_init_context(&context);
+    if (ret) {
+        *minor_status = ret;
+        return GSS_S_FAILURE;
+    }
+
+    ret = krb5_unparse_name(context, cred->impersonator, &impersonator);
+    if (ret) {
+        krb5_free_context(context);
+        *minor_status = ret;
+        return GSS_S_FAILURE;
+    }
+
+    rep.value = impersonator;
+    rep.length = strlen(impersonator);
+    major = generic_gss_add_buffer_set_member(minor_status, &rep, data_set);
+
+    krb5_free_unparsed_name(context, impersonator);
+    krb5_free_context(context);
+    return major;
+}
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index 9facb3f..16d38e9 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -10,6 +10,7 @@ GSS_C_NT_STRING_UID_NAME
 GSS_C_NT_USER_NAME
 GSS_KRB5_NT_PRINCIPAL_NAME
 GSS_KRB5_CRED_NO_CI_FLAGS_X
+GSS_KRB5_GET_CRED_IMPERSONATOR
 GSS_C_MA_MECH_CONCRETE
 GSS_C_MA_MECH_PSEUDO
 GSS_C_MA_MECH_COMPOSITE
diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
index 5bc1e44..0400f8f 100644
--- a/src/tests/gssapi/t_s4u.c
+++ b/src/tests/gssapi/t_s4u.c
@@ -242,6 +242,7 @@ main(int argc, char *argv[])
     gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL;
     gss_name_t user = GSS_C_NO_NAME, target = GSS_C_NO_NAME;
     gss_OID_set mechs;
+    gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
 
     if (argc < 2 || argc > 5) {
         fprintf(stderr, "Usage: %s [--spnego] [user] "
@@ -305,6 +306,25 @@ main(int argc, char *argv[])
         fprintf(stderr, "\n");
     }
 
+    if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+        /* Inquire impersonator status. */
+        major = gss_inquire_cred_by_oid(&minor, user_cred_handle,
+                                        GSS_KRB5_GET_CRED_IMPERSONATOR,
+                                        &bufset);
+        check_gsserr("gss_inquire_cred_by_oid", major, minor);
+        if (bufset->count == 0)
+            errout("gss_inquire_cred_by_oid(user) returned NO impersonator");
+        (void)gss_release_buffer_set(&minor, &bufset);
+
+        major = gss_inquire_cred_by_oid(&minor, impersonator_cred_handle,
+                                        GSS_KRB5_GET_CRED_IMPERSONATOR,
+                                        &bufset);
+        check_gsserr("gss_inquire_cred_by_oid", major, minor);
+        if (bufset->count != 0)
+            errout("gss_inquire_cred_by_oid(svc) returned an impersonator");
+        (void)gss_release_buffer_set(&minor, &bufset);
+    }
+
     (void)gss_release_name(&minor, &user);
     (void)gss_release_name(&minor, &target);
     (void)gss_release_cred(&minor, &delegated_cred_handle);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.