Properly implement neg_mechs & GM_USE_MG_CRED
authorNicolas Williams <nico@twosigma.com>
Sun, 19 Apr 2020 03:15:00 +0000 (22:15 -0500)
committerNicolas Williams <nico@twosigma.com>
Tue, 21 Apr 2020 05:21:32 +0000 (00:21 -0500)
SPNEGO was already using union creds.  Now make the mechglue know about
it, delete all of the cred-related SPNEGO stubs that are now not called
(lib/gssapi/spnego/cred_stubs.c), and implement gss_get/set_neg_mechs()
by storing the OID set in the union cred.

This commit was essentially authored as much if not more by Luke Howard
<lukeh at padl.com> as much as by the listed author.

20 files changed:
lib/gssapi/Makefile.am
lib/gssapi/NTMakefile
lib/gssapi/gssapi_mech.h
lib/gssapi/krb5/external.c
lib/gssapi/mech/cred.c
lib/gssapi/mech/cred.h
lib/gssapi/mech/gss_acquire_cred_from.c
lib/gssapi/mech/gss_add_cred_from.c
lib/gssapi/mech/gss_cred.c
lib/gssapi/mech/gss_get_neg_mechs.c
lib/gssapi/mech/gss_inquire_cred.c
lib/gssapi/mech/gss_mech_switch.c
lib/gssapi/mech/gss_set_neg_mechs.c
lib/gssapi/netlogon/external.c
lib/gssapi/ntlm/external.c
lib/gssapi/spnego/accept_sec_context.c
lib/gssapi/spnego/compat.c
lib/gssapi/spnego/cred_stubs.c [deleted file]
lib/gssapi/spnego/external.c
lib/gssapi/test_context.c

index fa8c01fbf047c32e8f5947787182e3d1d1084f33..0b1c7ff3272f7b3f71d85b4ecdf6a2d4baacb05a 100644 (file)
@@ -171,7 +171,6 @@ spnegosrc = \
        spnego/accept_sec_context.c \
        spnego/compat.c \
        spnego/context_stubs.c \
-       spnego/cred_stubs.c \
        spnego/external.c \
        spnego/init_sec_context.c \
        spnego/negoex_ctx.c \
index e153a0ce25b6c3b380717b0e5a83ac7188e6a089..185f63c4072ed60e4bb22b603518655b0f96aaca 100644 (file)
@@ -187,7 +187,6 @@ spnegosrc = \
        spnego/accept_sec_context.c \
        spnego/compat.c \
        spnego/context_stubs.c \
-       spnego/cred_stubs.c \
        spnego/external.c \
        spnego/init_sec_context.c \
        spnego/negoex_ctx.c \
@@ -431,7 +430,6 @@ libgssapi_OBJs = \
        $(OBJ)\spnego/accept_sec_context.obj \
        $(OBJ)\spnego/compat.obj \
        $(OBJ)\spnego/context_stubs.obj \
-       $(OBJ)\spnego/cred_stubs.obj \
        $(OBJ)\spnego/external.obj \
        $(OBJ)\spnego/init_sec_context.obj \
        $(OBJ)\spnego/negoex_ctx.obj \
index 1199bb6b8ebf00c12ec64f714d4e0c872d628bdf..fa027f805a2f2036337fedf9af819fd33965e424 100644 (file)
@@ -485,16 +485,6 @@ _gss_store_cred_into2_t(OM_uint32 *minor_status,
                        gss_cred_usage_t *cred_usage_stored,
                         gss_buffer_set_t *env);
 
-typedef OM_uint32 GSSAPI_CALLCONV
-_gss_set_neg_mechs_t(OM_uint32 *minor_status,
-                    gss_cred_id_t cred_handle,
-                    const gss_OID_set mechs);
-
-typedef OM_uint32 GSSAPI_CALLCONV
-_gss_get_neg_mechs_t(OM_uint32 *minor_status,
-                    gss_const_cred_id_t cred_handle,
-                    gss_OID_set *mechs);
-
 typedef OM_uint32 GSSAPI_CALLCONV
 _gss_query_mechanism_info_t(OM_uint32 *minor_status,
                            gss_const_OID mech_oid,
@@ -629,8 +619,6 @@ typedef struct gssapi_mech_interface_desc {
         _gss_duplicate_cred_t           *gm_duplicate_cred;
        _gss_add_cred_from_t            *gm_add_cred_from;
        _gss_store_cred_into_t          *gm_store_cred_into;
-       _gss_set_neg_mechs_t            *gm_set_neg_mechs;
-       _gss_get_neg_mechs_t            *gm_get_neg_mechs;
        _gss_query_mechanism_info_t     *gm_query_mechanism_info;
        _gss_query_meta_data_t          *gm_query_meta_data;
        _gss_exchange_meta_data_t       *gm_exchange_meta_data;
index 2562ef68afb332882e99333602304504cc904cbd..045d554976978e966b0564429ba12b02452d32d8 100644 (file)
@@ -391,8 +391,6 @@ static gssapi_mech_interface_desc krb5_mech = {
     _gsskrb5_duplicate_cred,
     _gsskrb5_add_cred_from,
     _gsskrb5_store_cred_into,
-    NULL, /* gm_set_neg_mechs */
-    NULL, /* gm_get_neg_mechs */
     NULL, /* gm_query_mechanism_info */
     NULL, /* gm_query_meta_data */
     NULL, /* gm_exchange_meta_data */
index aa0b89d8a68058fe1102719800db886c1a53a9cf..1a9ee61433e577a7e78a0d972c22ae27c12c70d7 100644 (file)
@@ -42,7 +42,11 @@ release_mech_cred(OM_uint32 *minor, struct _gss_mechanism_cred *mc)
 {
        OM_uint32 major;
 
-       major = mc->gmc_mech->gm_release_cred(minor, &mc->gmc_cred);
+        if (mc->gmc_mech->gm_release_cred != NULL)
+               major = mc->gmc_mech->gm_release_cred(minor, &mc->gmc_cred);
+       else
+               major = GSS_S_COMPLETE;
+
        free(mc);
 
        return major;
index d45067110e69c4551f0a4f74dab2e24c3694fc49..eed4a824d0f4c0ae635b589f93e2d4a7b1deff5b 100644 (file)
@@ -37,6 +37,7 @@ HEIM_TAILQ_HEAD(_gss_mechanism_cred_list, _gss_mechanism_cred);
 
 struct _gss_cred {
        struct _gss_mechanism_cred_list gc_mc;
+       gss_OID_set gc_neg_mechs;
 };
 
 struct _gss_cred *
index d32ebf6cb1b1227db94bd1c48524c772d118b7d3..bcae629d1cb6262fdb9b62b274b5c831d383d6f8 100644 (file)
@@ -149,7 +149,7 @@ gss_acquire_cred_from(OM_uint32 *minor_status,
     struct _gss_cred *cred = NULL;
     size_t i;
     OM_uint32 min_time = GSS_C_INDEFINITE;
-    gss_OID_set mechs;
+    gss_OID_set mechs = GSS_C_NO_OID_SET;
 
     *minor_status = 0;
     if (output_cred_handle == NULL)
@@ -162,28 +162,40 @@ gss_acquire_cred_from(OM_uint32 *minor_status,
 
     _gss_load_mech();
 
-    if (desired_mechs) {
-       int match = 0;
+    if (desired_mechs != GSS_C_NO_OID_SET) {
+       int only_mg_cred_mechs = -1;
 
        for (i = 0; i < desired_mechs->count; i++) {
-           gss_test_oid_set_member(minor_status, &desired_mechs->elements[i],
-                                   _gss_mech_oids, &match);
-           if (match)
-               break;
+           m = __gss_get_mechanism(&desired_mechs->elements[i]);
+           if (m != NULL) {
+               if ((m->gm_flags & GM_USE_MG_CRED) == 0)
+                   only_mg_cred_mechs = 0;
+               else if (only_mg_cred_mechs == -1)
+                   only_mg_cred_mechs = 1;
+           }
        }
-       if (!match) {
+       /*
+        * Now SPNEGO supports GM_USE_MG_CRED it's no longer necessary
+        * to specifically acquire SPNEGO credentials. If the caller
+        * did not specify any concrete mechanisms then we will acquire
+        * credentials for all of them.
+        */
+       if (only_mg_cred_mechs == -1) {
            *minor_status = 0;
            major_status = GSS_S_BAD_MECH;
            goto cleanup;
-       }
-       mechs = desired_mechs;
+       } else if (only_mg_cred_mechs == 0)
+           mechs = desired_mechs;
+       else
+           mechs = _gss_mech_oids;
     } else
        mechs = _gss_mech_oids;
 
     cred = _gss_mg_alloc_cred();
     if (cred == NULL) {
        *minor_status = ENOMEM;
-       return GSS_S_FAILURE;
+       major_status = GSS_S_FAILURE;
+       goto cleanup;
     }
 
     if (actual_mechs) {
@@ -251,6 +263,24 @@ gss_acquire_cred_from(OM_uint32 *minor_status,
        goto cleanup;
     }
 
+    /* add all GM_USE_MG_CRED mechs such as SPNEGO */
+    if (actual_mechs != NULL) {
+       struct _gss_mech_switch *ms;
+
+       HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) {
+           m = &ms->gm_mech;
+
+           if ((m->gm_flags & GM_USE_MG_CRED) == 0)
+               continue;
+
+           major_status = gss_add_oid_set_member(minor_status,
+                                                 &m->gm_mech_oid,
+                                                 actual_mechs);
+           if (GSS_ERROR(major_status))
+               goto cleanup;
+       }
+    }
+
     *minor_status = 0;
     major_status = GSS_S_COMPLETE;
 
index d304061dbfda25946aa84bd77a3cab8edc5eb185..9f761e8a7f270684b6eda9a9f7927ba8655bf430 100644 (file)
@@ -88,14 +88,75 @@ _gss_mg_add_mech_cred(OM_uint32 *minor_status,
     } else
        major_status = GSS_S_UNAVAILABLE;
 
-    if (major_status == GSS_S_COMPLETE && out)
+    if (major_status == GSS_S_COMPLETE && out) {
+       heim_assert(new_mc->gmc_cred != GSS_C_NO_CREDENTIAL,
+                   "mechanism gss_add_cred did not return a cred");
        *out = new_mc;
-    else
+    else
         free(new_mc);
 
     return major_status;
 }
 
+static OM_uint32
+add_mech_cred_internal(OM_uint32 *minor_status,
+                      gss_const_name_t desired_name,
+                      gssapi_mech_interface m,
+                      gss_cred_usage_t cred_usage,
+                      OM_uint32 initiator_time_req,
+                      OM_uint32 acceptor_time_req,
+                      gss_const_key_value_set_t cred_store,
+                      struct _gss_cred *mut_cred,
+                      OM_uint32 *initiator_time_rec,
+                      OM_uint32 *acceptor_time_rec)
+{
+    OM_uint32 major_status;
+    struct _gss_mechanism_cred *mc;
+    struct _gss_mechanism_name *mn;
+
+    heim_assert((m->gm_flags & GM_USE_MG_CRED) == 0,
+               "add_mech_cred_internal must be called with concrete mechanism");
+
+    if (desired_name != GSS_C_NO_NAME) {
+       major_status = _gss_find_mn(minor_status,
+                                   (struct _gss_name *)desired_name,
+                                   &m->gm_mech_oid, &mn);
+       if (major_status != GSS_S_COMPLETE)
+           return major_status;
+    } else
+       mn = NULL;
+
+    /*
+     * If we have an existing mechanism credential for mechanism m, then
+     * add the desired credential to it; otherwise, create a new one and
+     * add it to mut_cred.
+     */
+    HEIM_TAILQ_FOREACH(mc, &mut_cred->gc_mc, gmc_link) {
+       if (gss_oid_equal(&m->gm_mech_oid, mc->gmc_mech_oid))
+           break;
+    }
+
+    if (mc) {
+       major_status = _gss_mg_add_mech_cred(minor_status, m,
+                                            mc, mn, cred_usage,
+                                            initiator_time_req, acceptor_time_req,
+                                            cred_store, NULL,
+                                            initiator_time_rec, acceptor_time_rec);
+    } else {
+       struct _gss_mechanism_cred *new_mc = NULL;
+
+       major_status = _gss_mg_add_mech_cred(minor_status, m,
+                                            NULL, mn, cred_usage,
+                                            initiator_time_req, acceptor_time_req,
+                                            cred_store, &new_mc,
+                                            initiator_time_rec, acceptor_time_rec);
+       if (major_status == GSS_S_COMPLETE)
+           HEIM_TAILQ_INSERT_TAIL(&mut_cred->gc_mc, new_mc, gmc_link);
+    }
+
+    return major_status;
+}
+
 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
 gss_add_cred_from(OM_uint32 *minor_status,
     gss_cred_id_t input_cred_handle,
@@ -114,9 +175,6 @@ gss_add_cred_from(OM_uint32 *minor_status,
     gssapi_mech_interface m;
     gss_cred_id_t release_cred = GSS_C_NO_CREDENTIAL;
     struct _gss_cred *mut_cred;
-    struct _gss_mechanism_cred *mc;
-    struct _gss_mechanism_cred *new_mc = NULL;
-    struct _gss_mechanism_name *mn = NULL;
     OM_uint32 junk;
 
     *minor_status = 0;
@@ -130,8 +188,7 @@ gss_add_cred_from(OM_uint32 *minor_status,
         *acceptor_time_rec = 0;
     if (actual_mechs)
         *actual_mechs = GSS_C_NO_OID_SET;
-    if ((m = __gss_get_mechanism(desired_mech)) == NULL ||
-       (m->gm_flags & GM_USE_MG_CRED))
+    if ((m = __gss_get_mechanism(desired_mech)) == NULL)
         return GSS_S_BAD_MECH;
     if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
         output_cred_handle == NULL) {
@@ -162,45 +219,62 @@ gss_add_cred_from(OM_uint32 *minor_status,
         release_cred = (gss_cred_id_t)mut_cred;
     }
 
-    /* Find an MN, if any */
-    if (desired_name) {
-        major_status = _gss_find_mn(minor_status,
-                                    (struct _gss_name *)desired_name,
-                                    desired_mech, &mn);
-        if (major_status != GSS_S_COMPLETE)
-            goto done;
-    }
+    if (m->gm_flags & GM_USE_MG_CRED) {
+       struct _gss_mech_switch *ms;
+       OM_uint32 initiator_time_min = GSS_C_INDEFINITE;
+       OM_uint32 acceptor_time_min = GSS_C_INDEFINITE;
 
-    /*
-     * We go through all the mc attached to the input_cred_handle and check the
-     * mechanism.  If it matches, we call gss_add_cred for that mechanism,
-     * otherwise we just add a new mc.
-     */
-    HEIM_TAILQ_FOREACH(mc, &mut_cred->gc_mc, gmc_link) {
-        if (!gss_oid_equal(mc->gmc_mech_oid, desired_mech))
-            continue;
-        major_status = _gss_mg_add_mech_cred(minor_status, m,
-                                            mc, mn, cred_usage,
-                                            initiator_time_req, acceptor_time_req,
-                                            cred_store, NULL,
-                                            initiator_time_rec, acceptor_time_rec);
-        if (major_status != GSS_S_COMPLETE)
-            _gss_mg_error(m, *minor_status);
-        goto done;
-    }
+       major_status = GSS_S_UNAVAILABLE; /* in case of no mechs */
+
+       if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+           HEIM_TAILQ_FOREACH(ms, &_gss_mechs, gm_link) {
+               m = &ms->gm_mech; /* for _gss_mg_error() */
+
+               if (m->gm_flags & GM_USE_MG_CRED)
+                   continue;
+
+               major_status = add_mech_cred_internal(minor_status, desired_name, m,
+                                                     cred_usage,
+                                                     initiator_time_req, acceptor_time_req,
+                                                     cred_store, mut_cred,
+                                                     initiator_time_rec, acceptor_time_rec);
+               if (major_status != GSS_S_COMPLETE)
+                   continue;
 
-    major_status = _gss_mg_add_mech_cred(minor_status, m, NULL, mn, cred_usage,
-                                        initiator_time_req, acceptor_time_req,
-                                        cred_store, &new_mc,
-                                        initiator_time_rec, acceptor_time_rec);
-    if (major_status != GSS_S_COMPLETE) {
-        _gss_mg_error(m, *minor_status);
-        goto done;
+               if (initiator_time_rec && *initiator_time_rec < initiator_time_min)
+                   initiator_time_min = *initiator_time_rec;
+               if (acceptor_time_rec && *acceptor_time_rec < acceptor_time_min)
+                   acceptor_time_min = *acceptor_time_rec;
+           }
+       } else {
+           OM_uint32 lifetime;
+           gss_cred_usage_t usage = GSS_C_BOTH;
+
+           major_status = gss_inquire_cred(minor_status, input_cred_handle,
+                                           NULL, &lifetime, &usage, NULL);
+           if (major_status == GSS_S_COMPLETE) {
+               if (usage == GSS_C_BOTH || usage == GSS_C_INITIATE)
+                   initiator_time_min = lifetime;
+               if (usage == GSS_C_BOTH || usage == GSS_C_ACCEPT)
+                   acceptor_time_min = lifetime;
+           }
+       }
+
+       if (initiator_time_rec)
+           *initiator_time_rec = initiator_time_min;
+       if (acceptor_time_rec)
+           *acceptor_time_rec = acceptor_time_min;
+    } else {
+       major_status = add_mech_cred_internal(minor_status, desired_name, m,
+                                             cred_usage,
+                                             initiator_time_req, acceptor_time_req,
+                                             cred_store, mut_cred,
+                                             initiator_time_rec, acceptor_time_rec);
     }
-    HEIM_TAILQ_INSERT_TAIL(&mut_cred->gc_mc, new_mc, gmc_link);
-    new_mc = NULL;
 
-done:
+    if (major_status != GSS_S_COMPLETE)
+       _gss_mg_error(m, *minor_status);
+
     /* Lastly, we have to inquire the cred to get the actual_mechs */
     if (major_status == GSS_S_COMPLETE && actual_mechs != NULL) {
         major_status = gss_inquire_cred(minor_status,
@@ -213,7 +287,6 @@ done:
     } else {
         gss_release_cred(&junk, &release_cred);
     }
-    free(new_mc);
     return major_status;
 }
 
index 94642c5870c8fa90f332b9b6cb456e742c988e8c..ee2853222c0acd17b5f1ddcd3b026b8f9fcb80e8 100644 (file)
 #include "mech_locl.h"
 #include <krb5.h>
 
+static OM_uint32
+export_oid_set(OM_uint32 *minor_status,
+              gss_const_OID mech,
+              gss_const_OID_set oids,
+              krb5_storage *sp)
+{
+    krb5_error_code ret;
+    krb5_data data;
+    size_t i, len;
+
+    data.length = mech->length;
+    data.data = mech->elements;
+
+    ret = krb5_store_data(sp, data);
+    if (ret)
+       goto out;
+
+    for (i = 0, len = 0; i < oids->count; i++)
+       len += 4 + oids->elements[i].length;
+
+    ret = krb5_store_uint32(sp, len);
+    if (ret)
+       goto out;
+
+    for (i = 0; i < oids->count; i++) {
+       data.length = oids->elements[i].length;
+       data.data = oids->elements[i].elements;
+
+       ret = krb5_store_data(sp, data);
+       if (ret)
+           goto out;
+    }
+
+    ret = krb5_storage_to_data(sp, &data);
+    if (ret)
+       goto out;
+
+out:
+    *minor_status = ret;
+    return ret ? GSS_S_FAILURE : GSS_S_COMPLETE;
+}
+
 /*
  * format: any number of:
  *     mech-len: int32
  *     mech-data: char * (not alligned)
  *     cred-len: int32
  *     cred-data char * (not alligned)
+ *
+ * where neg_mechs is encoded for GSS_SPNEGO_MECHANISM
 */
 
 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
@@ -99,6 +143,15 @@ gss_export_cred(OM_uint32 * minor_status,
        _gss_secure_release_buffer(minor_status, &buffer);
     }
 
+    if (cred->gc_neg_mechs != GSS_C_NO_OID_SET) {
+       major = export_oid_set(minor_status, GSS_SPNEGO_MECHANISM,
+                              cred->gc_neg_mechs, sp);
+       if (major != GSS_S_COMPLETE) {
+           krb5_storage_free(sp);
+           return major;
+       }
+    }
+
     ret = krb5_storage_to_data(sp, &data);
     krb5_storage_free(sp);
     if (ret) {
@@ -120,6 +173,66 @@ gss_export_cred(OM_uint32 * minor_status,
     return GSS_S_COMPLETE;
 }
 
+static OM_uint32
+import_oid_set(OM_uint32 *minor_status,
+              gss_const_buffer_t token,
+              gss_OID_set *oids)
+{
+    OM_uint32 major, junk;
+    krb5_error_code ret;
+    krb5_storage *sp = NULL;
+
+    *oids = GSS_C_NO_OID_SET;
+
+    if (token->length == 0)
+       return GSS_S_COMPLETE;
+
+    major = gss_create_empty_oid_set(minor_status, oids);
+    if (major != GSS_S_COMPLETE)
+       goto out;
+
+    sp = krb5_storage_from_readonly_mem(token->value, token->length);
+    if (sp == NULL) {
+       *minor_status = ENOMEM;
+       major = GSS_S_FAILURE;
+       goto out;
+    }
+
+    while (1) {
+       gss_OID_desc oid;
+       krb5_data data;
+
+       ret = krb5_ret_data(sp, &data);
+       if (ret == HEIM_ERR_EOF)
+           break;
+       else if (ret) {
+           *minor_status = ret;
+           major = GSS_S_FAILURE;
+           goto out;
+       }
+
+       oid.elements = data.data;
+       oid.length = (OM_uint32)data.length;
+
+       major = gss_add_oid_set_member(minor_status, &oid, oids);
+       if (major != GSS_S_COMPLETE) {
+           krb5_data_free(&data);
+           goto out;
+       }
+       krb5_data_free(&data);
+    }
+
+    major = GSS_S_COMPLETE;
+    *minor_status = 0;
+
+out:
+    if (major != GSS_S_COMPLETE)
+       gss_release_oid_set(&junk, oids);
+    krb5_storage_free(sp);
+
+    return major;
+}
+
 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
 gss_import_cred(OM_uint32 * minor_status,
                gss_buffer_t token,
@@ -179,7 +292,8 @@ gss_import_cred(OM_uint32 * minor_status,
            goto out;
        }
 
-       if (m->gm_import_cred == NULL) {
+       if (m->gm_import_cred == NULL &&
+           !gss_oid_equal(&m->gm_mech_oid, GSS_SPNEGO_MECHANISM)) {
            *minor_status = 0;
            major = GSS_S_BAD_MECH;
            goto out;
@@ -195,6 +309,15 @@ gss_import_cred(OM_uint32 * minor_status,
        buffer.value = data.data;
        buffer.length = data.length;
 
+       if (gss_oid_equal(&m->gm_mech_oid, GSS_SPNEGO_MECHANISM)) {
+           major = import_oid_set(minor_status, &buffer, &cred->gc_neg_mechs);
+           krb5_data_free(&data);
+           if (major != GSS_S_COMPLETE)
+               goto out;
+           else
+               continue;
+       }
+
        major = m->gm_import_cred(minor_status,
                                  &buffer, &mcred);
        krb5_data_free(&data);
index 500db0cc4511348be3cd91ff3322cb6d2097ce18..cbc37863945d5e13e36dbfbe37116b6a340c499b 100644 (file)
 #include "mech_locl.h"
 
 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
-gss_get_neg_mechs (OM_uint32 *minor_status,
-                  gss_const_cred_id_t cred_handle,
-                  gss_OID_set *mechs)
+gss_get_neg_mechs(OM_uint32 *minor_status,
+                 gss_const_cred_id_t cred_handle,
+                 gss_OID_set *mechs)
 {
     struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
-    OM_uint32 major, minor;
-    gss_cred_id_t tmp_cred = GSS_C_NO_CREDENTIAL;
-    struct _gss_mechanism_cred *mc;
 
     if (minor_status == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
     *minor_status = 0;
 
     if (mechs == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;
-    *mechs = GSS_C_NO_OID_SET;
-
-    _gss_load_mech();
-
-    if (cred == NULL) {
-       major = gss_acquire_cred(minor_status, GSS_C_NO_NAME, GSS_C_INDEFINITE,
-                                GSS_C_NO_OID_SET, GSS_C_BOTH,
-                                &tmp_cred, NULL, NULL);
-       if (GSS_ERROR(major))
-           return major;
-
-       cred = (struct _gss_cred *)tmp_cred;
-    }
-
-    major = gss_create_empty_oid_set(minor_status, mechs);
-    if (GSS_ERROR(major))
-       goto cleanup;
-
-    major = GSS_S_UNAVAILABLE;
-
-    HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
-       gssapi_mech_interface m;
-       gss_OID_set mechs2 = GSS_C_NO_OID_SET;
-       size_t i;
-
-       m = mc->gmc_mech;
-       if (m == NULL) {
-           major = GSS_S_BAD_MECH;
-           goto cleanup;
-       }
-
-       if (m->gm_get_neg_mechs == NULL)
-           continue;
-
-       major = m->gm_get_neg_mechs(minor_status, mc->gmc_cred, &mechs2);
-       if (GSS_ERROR(major))
-           goto cleanup;
-
-       if (mechs2 == GSS_C_NO_OID_SET)
-           continue;
-
-       for (i = 0; i < mechs2->count; i++) {
-           major = gss_add_oid_set_member(minor_status, &mechs2->elements[i],
-                                          mechs);
-           if (GSS_ERROR(major)) {
-               gss_release_oid_set(&minor, &mechs2);
-               goto cleanup;
-           }
-       }
-
-       gss_release_oid_set(&minor, &mechs2);
-    }
 
-cleanup:
-    if (tmp_cred)
-       gss_release_cred(&minor, &tmp_cred);
-    if (major == GSS_S_COMPLETE && *mechs == GSS_C_NO_OID_SET)
-       major = GSS_S_NO_CRED;
-    if (GSS_ERROR(major))
-       gss_release_oid_set(&minor, mechs);
+    if (cred->gc_neg_mechs != GSS_C_NO_OID_SET)
+        return gss_duplicate_oid_set(minor_status, cred->gc_neg_mechs, mechs);
 
-    return major;
+    return GSS_S_UNAVAILABLE;
 }
index f7408c84cb382e55f7dcc1d0958b95cfa2fa9de6..82cf34c42eacfe6f764cbac7c6572176f9fe7ac3 100644 (file)
@@ -99,6 +99,9 @@ gss_inquire_cred(OM_uint32 *minor_status,
                        gss_name_t mc_name = GSS_C_NO_NAME;
                        OM_uint32 mc_lifetime = GSS_C_INDEFINITE;
 
+                       heim_assert((mc->gmc_mech->gm_flags & GM_USE_MG_CRED) == 0,
+                                   "should not have mech creds for GM_USE_MG_CRED mechs");
+
                        if (mc->gmc_mech->gm_inquire_cred == NULL)
                                continue;
 
@@ -137,7 +140,8 @@ gss_inquire_cred(OM_uint32 *minor_status,
                        gss_name_t mc_name;
                        OM_uint32 mc_lifetime;
 
-                       if (m->gm_mech.gm_inquire_cred == NULL)
+                       if (m->gm_mech.gm_inquire_cred == NULL ||
+                           (m->gm_mech.gm_flags & GM_USE_MG_CRED))
                                continue;
 
                        major_status = m->gm_mech.gm_inquire_cred(minor_status,
@@ -174,6 +178,17 @@ gss_inquire_cred(OM_uint32 *minor_status,
                }
        }
 
+       if (found && mechanisms) {
+               /* GM_USE_MG_CRED mechs (SPNEGO) always can be used */
+               HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
+                       if ((m->gm_mech.gm_flags & GM_USE_MG_CRED) == 0)
+                               continue;
+
+                       gss_add_oid_set_member(minor_status,
+                                              m->gm_mech_oid, mechanisms);
+               }
+       }
+
        if (found == 0 || min_lifetime == 0) {
                gss_name_t n = (gss_name_t)name;
                if (n)
index e4a56f3ce95069da4d7c2cebd58355c813bdfd86..9085e962ff4497b85cd1c47074a4a7e37c14bdae 100644 (file)
@@ -417,8 +417,6 @@ _gss_load_mech(void)
                OPTSYM(duplicate_cred);
                OPTSYM(add_cred_from);
                OPTSYM(store_cred_into);
-               OPTSYM(set_neg_mechs);
-               OPTSYM(get_neg_mechs);
                OPTSPISYM(authorize_localname);
                OPTSPISPISYM(query_mechanism_info);
                OPTSPISPISYM(query_meta_data);
index 5402e9656013b1451fdb96f0bfe89026d6f4ca12..7c527b2ab41e6f037a2d05e0ab94ac71a9545e46 100644 (file)
 #include "mech_locl.h"
 
 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
-gss_set_neg_mechs (OM_uint32 *minor_status,
-                  gss_cred_id_t cred_handle,
-                  const gss_OID_set mechs)
+gss_set_neg_mechs(OM_uint32 *minor_status,
+                 gss_cred_id_t cred_handle,
+                 const gss_OID_set mechs)
 {
     struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
-    OM_uint32 major;
-    int found = 0;
+    OM_uint32 major_status, junk;
+    gss_OID_set tmp_mechs;
 
     if (minor_status == NULL)
        return GSS_S_CALL_INACCESSIBLE_WRITE;
+
     *minor_status = 0;
 
-    if (mechs == GSS_C_NO_OID_SET)
+    if (cred_handle == GSS_C_NO_CREDENTIAL || mechs == GSS_C_NO_OID_SET)
        return GSS_S_CALL_INACCESSIBLE_READ;
 
-    _gss_load_mech();
-
-    major = GSS_S_UNAVAILABLE;
-
-    if (cred == NULL) {
-       struct _gss_mech_switch *m;
-
-        HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
-           if (m->gm_mech.gm_set_neg_mechs == NULL)
-               continue;
-           major = m->gm_mech.gm_set_neg_mechs(minor_status,
-                                               GSS_C_NO_CREDENTIAL, mechs);
-           if (major == GSS_S_COMPLETE)
-               found++;
-           else
-               _gss_mg_error(&m->gm_mech, *minor_status);
-       }
-    } else {
-       struct _gss_mechanism_cred *mc;
-
-       HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
-           gssapi_mech_interface m;
-
-           m = mc->gmc_mech;
-           if (m == NULL)
-               return GSS_S_BAD_MECH;
-           if (m->gm_set_neg_mechs == NULL)
-               continue;
-           major = m->gm_set_neg_mechs(minor_status, mc->gmc_cred, mechs);
-           if (major == GSS_S_COMPLETE)
-               found++;
-           else
-               _gss_mg_error(m, *minor_status);
-       }
-    }
+    major_status = gss_duplicate_oid_set(minor_status, mechs, &tmp_mechs);
+    if (major_status != GSS_S_COMPLETE)
+       return major_status;
 
-    if (found) {
-       *minor_status = 0;
-       return GSS_S_COMPLETE;
-    }
+    gss_release_oid_set(&junk, &cred->gc_neg_mechs);
+    cred->gc_neg_mechs = tmp_mechs;
 
-    return major;
+    return GSS_S_COMPLETE;
 }
index 49a37cb826be2a2f4716cc68584072c618a7c6a8..7c0f81b1d21070c3aae156f27047906cb0ee084b 100644 (file)
@@ -100,8 +100,6 @@ static gssapi_mech_interface_desc netlogon_mech = {
     NULL, /* gm_duplicate_cred */
     NULL, /* gm_add_cred_from */
     NULL, /* gm_store_cred_into */
-    NULL, /* gm_set_neg_mechs */
-    NULL, /* gm_get_neg_mechs */
     NULL  /* gm_compat */
 };
 
index 02590c96d31c34a04072047107c90d0df92e715c..ed60c3eae3c3a37a418c80f19fcf1a5cee2f5e3c 100644 (file)
@@ -125,8 +125,6 @@ static gssapi_mech_interface_desc ntlm_mech = {
     NULL, /* gm_duplicate_cred */
     NULL, /* gm_add_cred_from */
     NULL, /* gm_store_cred_into */
-    NULL, /* gm_set_neg_mechs */
-    NULL, /* gm_get_neg_mechs */
     NULL, /* gm_query_mechanism_info */
     NULL, /* gm_query_meta_data */
     NULL, /* gm_exchange_meta_data */
index 910d7e2c73bae0ecc10c41191ae559e0f2ef0aae..89311a1e75c5bce6ca759fa9a07a9f8f5047373e 100644 (file)
@@ -601,8 +601,7 @@ acceptor_start
     gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
     gss_buffer_desc mech_output_token;
     gssspnego_ctx ctx;
-    int get_mic = 0;
-    int first_ok = 0;
+    int get_mic = 0, first_ok = 0, canonical_order;
     gss_const_OID advertised_mech = GSS_C_NO_OID;
 
     memset(&nt, 0, sizeof(nt));
@@ -676,7 +675,8 @@ acceptor_start
     if (acceptor_cred_handle != GSS_C_NO_CREDENTIAL)
        ret = _gss_spnego_inquire_cred_mechs(minor_status,
                                             acceptor_cred_handle,
-                                            &supported_mechs);
+                                            &supported_mechs,
+                                            &canonical_order);
     else
        ret = _gss_spnego_indicate_mechs(minor_status, &supported_mechs);
     if (ret != GSS_S_COMPLETE)
index 1e09addacc6471a1ef50df11e1bc0c5f0f7b9ef4..6cfe5526631cabe60207cd744c0fcf0895e5ca7f 100644 (file)
@@ -397,24 +397,21 @@ _gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
     OM_uint32 ret, minor;
     OM_uint32 first_major = GSS_S_BAD_MECH, first_minor = 0;
     size_t i;
-    int added_negoex = FALSE;
+    int added_negoex = FALSE, canonical_order = FALSE;
 
     mechtypelist->len = 0;
     mechtypelist->val = NULL;
 
     if (cred_handle != GSS_C_NO_CREDENTIAL)
-       ret = _gss_spnego_inquire_cred_mechs(minor_status,
-                                            cred_handle, &supported_mechs);
+       ret = _gss_spnego_inquire_cred_mechs(minor_status, cred_handle,
+                                            &supported_mechs, &canonical_order);
     else
        ret = _gss_spnego_indicate_mechs(minor_status, &supported_mechs);
     if (ret != GSS_S_COMPLETE)
        return ret;
 
-    /*
-     * XXX when gss_set_neg_mechs() obeys application order this should
-     * apply only to the default mech list
-     */
-    order_mechs_by_flags(supported_mechs, req_flags);
+    if (!canonical_order)
+       order_mechs_by_flags(supported_mechs, req_flags);
 
     heim_assert(supported_mechs != GSS_C_NO_OID_SET,
                "NULL mech set returned by SPNEGO inquire/indicate mechs");
@@ -626,40 +623,48 @@ _gss_spnego_indicate_mechs(OM_uint32 *minor_status,
 OM_uint32
 _gss_spnego_inquire_cred_mechs(OM_uint32 *minor_status,
                               gss_const_cred_id_t cred,
-                              gss_OID_set *mechs_p)
+                              gss_OID_set *mechs_p,
+                              int *canonical_order)
 {
     OM_uint32 ret, junk;
     gss_OID_set cred_mechs = GSS_C_NO_OID_SET;
-    gss_OID_set mechs = GSS_C_NO_OID_SET;
+    gss_OID_set negotiable_mechs = GSS_C_NO_OID_SET;
     size_t i;
 
     *mechs_p = GSS_C_NO_OID_SET;
+    *canonical_order = FALSE;
 
     heim_assert(cred != GSS_C_NO_CREDENTIAL, "Invalid null credential handle");
 
-    ret = gss_inquire_cred(minor_status, cred, NULL, NULL, NULL, &cred_mechs);
-    if (ret != GSS_S_COMPLETE)
-       goto out;
+    ret = gss_get_neg_mechs(minor_status, cred, &cred_mechs);
+    if (ret == GSS_S_COMPLETE) {
+       *canonical_order = TRUE;
+    } else {
+       ret = gss_inquire_cred(minor_status, cred, NULL, NULL, NULL, &cred_mechs);
+       if (ret != GSS_S_COMPLETE)
+           goto out;
+    }
 
-    heim_assert(cred_mechs != GSS_C_NO_OID_SET,
-               "gss_inquire_cred succeeded but returned null OID set");
+    heim_assert(cred_mechs != GSS_C_NO_OID_SET && cred_mechs->count > 0,
+               "gss_inquire_cred succeeded but returned no mechanisms");
 
-    ret = _gss_spnego_indicate_mechs(minor_status, &mechs);
+    ret = _gss_spnego_indicate_mechs(minor_status, &negotiable_mechs);
     if (ret != GSS_S_COMPLETE)
        goto out;
 
-    heim_assert(mechs != GSS_C_NO_OID_SET,
+    heim_assert(negotiable_mechs != GSS_C_NO_OID_SET,
                "_gss_spnego_indicate_mechs succeeded but returned null OID set");
 
     ret = gss_create_empty_oid_set(minor_status, mechs_p);
     if (ret != GSS_S_COMPLETE)
        goto out;
 
+    /* Filter credential mechs by negotiable mechs, order by credential mechs */
     for (i = 0; i < cred_mechs->count; i++) {
        gss_OID cred_mech = &cred_mechs->elements[i];
        int present = 0;
 
-       gss_test_oid_set_member(&junk, cred_mech, mechs, &present);
+       gss_test_oid_set_member(&junk, cred_mech, negotiable_mechs, &present);
        if (!present)
            continue;
 
@@ -672,7 +677,7 @@ out:
     if (ret != GSS_S_COMPLETE)
        gss_release_oid_set(&junk, mechs_p);
     gss_release_oid_set(&junk, &cred_mechs);
-    gss_release_oid_set(&junk, &mechs);
+    gss_release_oid_set(&junk, &negotiable_mechs);
 
     return ret;
 }
diff --git a/lib/gssapi/spnego/cred_stubs.c b/lib/gssapi/spnego/cred_stubs.c
deleted file mode 100644 (file)
index 0124c8f..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2004, 2018, PADL Software Pty Ltd.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of PADL Software nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "spnego_locl.h"
-#include <gssapi_mech.h>
-
-/*
- * For now, just a simple wrapper that avoids recursion. When
- * we support gss_{get,set}_neg_mechs() we will need to expose
- * more functionality.
- */
-OM_uint32 GSSAPI_CALLCONV _gss_spnego_acquire_cred_from
-(OM_uint32 *minor_status,
- gss_const_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 ret, tmp;
-    gss_OID_set mechs;
-
-    *output_cred_handle = GSS_C_NO_CREDENTIAL;
-
-    ret = _gss_spnego_indicate_mechs(minor_status, &mechs);
-    if (ret != GSS_S_COMPLETE)
-       return ret;
-
-    ret = gss_acquire_cred_from(minor_status, desired_name,
-                               time_req, mechs,
-                               cred_usage, cred_store,
-                               output_cred_handle,
-                               actual_mechs, time_rec);
-    gss_release_oid_set(&tmp, &mechs);
-
-    return ret;
-}
-
-OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_cred
-           (OM_uint32 * minor_status,
-            gss_const_cred_id_t cred_handle,
-            gss_name_t * name,
-            OM_uint32 * lifetime,
-            gss_cred_usage_t * cred_usage,
-            gss_OID_set * mechanisms
-           )
-{
-    /*
-     * A wrapper around the mechglue is required to error out
-     * where cred_handle == GSS_C_NO_CREDENTIAL, otherwise we
-     * would infinitely recurse.
-     */
-    if (cred_handle == GSS_C_NO_CREDENTIAL) {
-       *minor_status = 0;
-       return GSS_S_NO_CRED;
-    }
-
-    return gss_inquire_cred(minor_status, cred_handle, name,
-                           lifetime, cred_usage, mechanisms);
-}
-
-OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_cred_by_mech (
-            OM_uint32 * minor_status,
-            gss_const_cred_id_t cred_handle,
-            const gss_OID mech_type,
-            gss_name_t * name,
-            OM_uint32 * initiator_lifetime,
-            OM_uint32 * acceptor_lifetime,
-            gss_cred_usage_t * cred_usage
-           )
-{
-    /* Similar to _gss_spnego_inquire_cred(), wrapper is required */
-    heim_assert(gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM),
-               "Mechglue called inquire_cred_by_mech with wrong OID");
-
-    *minor_status = 0;
-    return GSS_S_BAD_MECH;
-}
-
-OM_uint32 GSSAPI_CALLCONV
-_gss_spnego_set_cred_option (OM_uint32 *minor_status,
-                            gss_cred_id_t *cred_handle,
-                            const gss_OID object,
-                            const gss_buffer_t value)
-{
-    /* Similar to _gss_spnego_inquire_cred(), wrapper is required */
-    if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) {
-       *minor_status = 0;
-       return GSS_S_NO_CRED;
-    }
-
-    return gss_set_cred_option(minor_status,
-                             cred_handle,
-                             object,
-                             value);
-}
-
-
-OM_uint32 GSSAPI_CALLCONV
-_gss_spnego_set_neg_mechs (OM_uint32 *minor_status,
-                          gss_cred_id_t cred_handle,
-                          const gss_OID_set mech_list)
-{
-    OM_uint32 major, minor;
-    gss_OID_set mechs = GSS_C_NO_OID_SET;
-    size_t i;
-
-    if (cred_handle != GSS_C_NO_CREDENTIAL) {
-       major = gss_inquire_cred(minor_status, cred_handle,
-                                NULL, NULL, NULL, &mechs);
-       if (GSS_ERROR(major))
-           return major;
-
-       for (i = 0; i < mechs->count; i++) {
-           int present;
-
-           major = gss_test_oid_set_member(minor_status,
-                                           &mechs->elements[i],
-                                           mech_list, &present);
-           if (GSS_ERROR(major))
-               break;
-
-           if (!present) {
-               major = gss_release_cred_by_mech(minor_status,
-                                                cred_handle,
-                                                &mechs->elements[i]);
-               if (GSS_ERROR(major))
-                   break;
-           }
-       }
-    } else {
-       /*
-        * RFC 4178 says that GSS_Set_neg_mechs() on NULL credential sets
-        * the negotiable mechs for the default credential, but neither
-        * MIT nor Heimdal support this presently.
-        */
-       major = GSS_S_NO_CRED;
-    }
-
-    gss_release_oid_set(&minor, &mechs);
-
-    return major;
-}
-
-OM_uint32 GSSAPI_CALLCONV
-_gss_spnego_get_neg_mechs (OM_uint32 *minor_status,
-                          gss_const_cred_id_t cred_handle,
-                          gss_OID_set *mech_list)
-{
-    return gss_inquire_cred(minor_status, cred_handle,
-                           NULL, NULL, NULL, mech_list);
-}
index 9ced91ead25ee564c62dd3388aacc58c8c224c82..99b3412d862a1a989803b4d7494a3162b1cde26e 100644 (file)
@@ -88,9 +88,9 @@ static gssapi_mech_interface_desc spnego_mech = {
     GMI_VERSION,
     "spnego",
     {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02") },
-    0,
+    GM_USE_MG_CRED,
     NULL, /* gm_acquire_cred */
-    gss_release_cred,
+    NULL, /* gm_release_cred */
     _gss_spnego_init_sec_context,
     _gss_spnego_accept_sec_context,
     _gss_spnego_process_context_token,
@@ -107,11 +107,11 @@ static gssapi_mech_interface_desc spnego_mech = {
     _gss_spnego_import_name,
     _gss_spnego_export_name,
     _gss_spnego_release_name,
-    _gss_spnego_inquire_cred,
+    NULL, /* gm_inquire_cred */
     _gss_spnego_inquire_context,
     _gss_spnego_wrap_size_limit,
-    gss_add_cred,
-    _gss_spnego_inquire_cred_by_mech,
+    NULL, /* gm_add_cred */
+    NULL, /* gm_inquire_cred_by_mech */
     _gss_spnego_export_sec_context,
     _gss_spnego_import_sec_context,
     NULL /* _gss_spnego_inquire_names_for_mech */,
@@ -119,17 +119,17 @@ static gssapi_mech_interface_desc spnego_mech = {
     _gss_spnego_canonicalize_name,
     _gss_spnego_duplicate_name,
     _gss_spnego_inquire_sec_context_by_oid,
-    gss_inquire_cred_by_oid,
+    NULL, /* gm_inquire_cred_by_oid */
     _gss_spnego_set_sec_context_option,
-    _gss_spnego_set_cred_option,
+    NULL, /* gm_set_cred_option */
     _gss_spnego_pseudo_random,
     _gss_spnego_wrap_iov,
     _gss_spnego_unwrap_iov,
     _gss_spnego_wrap_iov_length,
     NULL,
-    gss_export_cred,
-    gss_import_cred,
-    _gss_spnego_acquire_cred_from,
+    NULL, /* gm_export_cred */
+    NULL, /* gm_import_cred */
+    NULL, /* gm_acquire_cred_from */
     NULL,
     NULL,
     NULL,
@@ -146,11 +146,9 @@ static gssapi_mech_interface_desc spnego_mech = {
     NULL, /* gm_set_name_attribute */
     NULL, /* gm_delete_name_attribute */
     NULL, /* gm_export_name_composite */
-    gss_duplicate_cred,
-    gss_add_cred_from,
+    NULL, /* gm_duplicate_cred */
+    NULL, /* gm_add_cred_from */
     NULL, /* gm_store_cred_into */
-    _gss_spnego_set_neg_mechs,
-    _gss_spnego_get_neg_mechs,
     NULL, /* gm_query_mechanism_info */
     NULL, /* gm_query_meta_data */
     NULL, /* gm_exchange_meta_data */
index 1462da190dfb00e8cbd6e81aa375efa537df9e00..b59bbd83ae01ec2a1af079b6d38e3054dc936c36 100644 (file)
@@ -627,6 +627,7 @@ main(int argc, char **argv)
     gss_OID_set mechoids = GSS_C_NO_OID_SET;
     gss_key_value_element_desc client_cred_elements[2];
     gss_key_value_set_desc client_cred_store;
+    gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
 
     setprogname(argv[0]);
 
@@ -756,7 +757,7 @@ main(int argc, char **argv)
                                                  mechoids,
                                                  GSS_C_INITIATE,
                                                  &client_cred,
-                                                 NULL,
+                                                 &actual_mechs,
                                                  NULL);
        if (GSS_ERROR(maj_stat)) {
             if (mechoids != GSS_C_NO_OID_SET && mechoids->count == 1)
@@ -775,13 +776,41 @@ main(int argc, char **argv)
                                         client_cred_store.count ? &client_cred_store
                                                                 : GSS_C_NO_CRED_STORE,
                                         &client_cred,
-                                        NULL,
+                                        &actual_mechs,
                                         NULL);
        if (GSS_ERROR(maj_stat))
            errx(1, "gss_acquire_cred: %s",
                 gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
     }
 
+    if (verbose_flag) {
+       size_t i;
+
+       printf("cred mechs:");
+       for (i = 0; i < actual_mechs->count; i++)
+           printf(" %s", oid_to_string(&actual_mechs->elements[i]));
+       printf("\n");
+    }
+
+    if (ei_cred_flag) {
+       gss_cred_id_t cred2 = GSS_C_NO_CREDENTIAL;
+       gss_buffer_desc cb;
+
+       maj_stat = gss_export_cred(&min_stat, client_cred, &cb);
+       if (maj_stat != GSS_S_COMPLETE)
+           errx(1, "export cred failed: %s",
+                gssapi_err(maj_stat, min_stat, NULL));
+
+       maj_stat = gss_import_cred(&min_stat, &cb, &cred2);
+       if (maj_stat != GSS_S_COMPLETE)
+           errx(1, "import cred failed: %s",
+                gssapi_err(maj_stat, min_stat, NULL));
+
+       gss_release_buffer(&min_stat, &cb);
+       gss_release_cred(&min_stat, &client_cred);
+       client_cred = cred2;
+    }
+
     if (limit_enctype_string) {
        krb5_error_code ret;
 
@@ -1242,6 +1271,7 @@ main(int argc, char **argv)
     }
 
     gss_release_cred(&min_stat, &client_cred);
+    gss_release_oid_set(&min_stat, &actual_mechs);
     empty_release();
 
     krb5_free_context(context);