summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2010-02-10 23:44:18 +0000
committerGreg Hudson <ghudson@mit.edu>2010-02-10 23:44:18 +0000
commit079eed2cf749702f75ddc385cf943fbab931f9d8 (patch)
treee4e548c13a58a0d4a55c8a37ba3b7405f9b830db /src/lib
parent11079f43e990d8150870a2c894e17e286f46c96c (diff)
downloadkrb5-079eed2cf749702f75ddc385cf943fbab931f9d8.tar.gz
krb5-079eed2cf749702f75ddc385cf943fbab931f9d8.tar.xz
krb5-079eed2cf749702f75ddc385cf943fbab931f9d8.zip
Implement gss_set_neg_mechs
Implement gss_set_neg_mechs in SPNEGO by intersecting the provided mech set with the mechanisms available in the union credential. As we now need space to hold the mech set, the SPNEGO credential is now a structure and not just a mechglue credential. t_spnego.c is a test program which exercises the new logic. Like the other GSSAPI tests, it is not run as part of "make check" at this time. ticket: 6658 target_version: 1.8 tags: pullup git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23715 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/gssapi/generic/gssapi.hin6
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c1
-rw-r--r--src/lib/gssapi/libgssapi_krb5.exports1
-rw-r--r--src/lib/gssapi/mechglue/Makefile.in3
-rw-r--r--src/lib/gssapi/mechglue/g_initialize.c2
-rw-r--r--src/lib/gssapi/mechglue/g_set_neg_mechs.c77
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h6
-rw-r--r--src/lib/gssapi/spnego/gssapiP_spnego.h14
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c272
9 files changed, 301 insertions, 81 deletions
diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin
index e60d04d872..fb82e3c4f5 100644
--- a/src/lib/gssapi/generic/gssapi.hin
+++ b/src/lib/gssapi/generic/gssapi.hin
@@ -805,6 +805,12 @@ gss_store_cred(
gss_OID_set *, /* elements_stored */
gss_cred_usage_t *);/* cred_usage_stored */
+OM_uint32 KRB5_CALLCONV
+gss_set_neg_mechs(
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ const gss_OID_set); /* mech_set */
+
#if TARGET_OS_MAC
# pragma pack(pop)
#endif
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index b68bc9a737..9e5ba76d9f 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -694,6 +694,7 @@ static struct gss_config krb5_mechanism = {
krb5_gss_map_name_to_any,
krb5_gss_release_any_name_mapping,
krb5_gss_pseudo_random,
+ NULL, /* set_neg_mechs */
};
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index e7f7b3609d..e038f50769 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -80,6 +80,7 @@ gss_release_oid
gss_release_oid_set
gss_seal
gss_set_name_attribute
+gss_set_neg_mechs
gss_set_sec_context_option
gss_sign
gss_store_cred
diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in
index 0858a4a989..f43571145a 100644
--- a/src/lib/gssapi/mechglue/Makefile.in
+++ b/src/lib/gssapi/mechglue/Makefile.in
@@ -54,6 +54,7 @@ SRCS = \
$(srcdir)/g_set_context_option.c \
$(srcdir)/g_set_cred_option.c \
$(srcdir)/g_set_name_attr.c \
+ $(srcdir)/g_set_neg_mechs.c \
$(srcdir)/g_sign.c \
$(srcdir)/g_store_cred.c \
$(srcdir)/g_unseal.c \
@@ -108,6 +109,7 @@ OBJS = \
$(OUTPRE)g_set_context_option.$(OBJEXT) \
$(OUTPRE)g_set_cred_option.$(OBJEXT) \
$(OUTPRE)g_set_name_attr.$(OBJEXT) \
+ $(OUTPRE)g_set_neg_mechs.$(OBJEXT) \
$(OUTPRE)g_sign.$(OBJEXT) \
$(OUTPRE)g_store_cred.$(OBJEXT) \
$(OUTPRE)g_unseal.$(OBJEXT) \
@@ -162,6 +164,7 @@ STLIBOBJS = \
g_set_context_option.o \
g_set_cred_option.o \
g_set_name_attr.o \
+ g_set_neg_mechs.o \
g_sign.o \
g_store_cred.o \
g_unseal.o \
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index e01d174742..70c2203912 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -775,6 +775,8 @@ build_dynamicMech(void *dl, const gss_OID mech_type)
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_release_any_name_mapping);
/* RFC 4401 (introduced in 1.8) */
GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_pseudo_random);
+ /* RFC 4178 (introduced in 1.8; gss_get_neg_mechs not implemented) */
+ GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_set_neg_mechs);
assert(mech_type != GSS_C_NO_OID);
diff --git a/src/lib/gssapi/mechglue/g_set_neg_mechs.c b/src/lib/gssapi/mechglue/g_set_neg_mechs.c
new file mode 100644
index 0000000000..167537675b
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_set_neg_mechs.c
@@ -0,0 +1,77 @@
+/*
+ * lib/gssapi/mechglue/g_set_neg_mechs.c
+ *
+ * Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Glue routine for gss_set_neg_mechs.
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_set_neg_mechs(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ const gss_OID_set mech_set)
+{
+ gss_union_cred_t union_cred;
+ gss_mechanism mech;
+ int i, avail;
+ OM_uint32 status;
+
+ if (minor_status == NULL)
+ return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+ if (cred_handle == GSS_C_NO_CREDENTIAL)
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED;
+
+ *minor_status = 0;
+
+ union_cred = (gss_union_cred_t) cred_handle;
+
+ avail = 0;
+ status = GSS_S_COMPLETE;
+ for (i = 0; i < union_cred->count; i++) {
+ mech = gssint_get_mechanism(&union_cred->mechs_array[i]);
+ if (mech == NULL) {
+ status = GSS_S_BAD_MECH;
+ break;
+ }
+
+ if (mech->gss_set_neg_mechs == NULL)
+ continue;
+
+ avail = 1;
+ status = (mech->gss_set_neg_mechs)(minor_status,
+ union_cred->cred_array[i],
+ mech_set);
+ if (status != GSS_S_COMPLETE) {
+ map_error(minor_status, mech);
+ break;
+ }
+ }
+
+ if (status == GSS_S_COMPLETE && !avail)
+ return GSS_S_UNAVAILABLE;
+ return status;
+}
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index 517ca481b9..3769caf876 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -583,6 +583,12 @@ typedef struct gss_config {
gss_buffer_t /* prf_out */
/* */);
+ OM_uint32 (*gss_set_neg_mechs)
+ (
+ OM_uint32 *, /* minor_status */
+ gss_cred_id_t, /* cred_handle */
+ const gss_OID_set /* mech_set */
+ /* */);
} *gss_mechanism;
/* This structure MUST NOT be used by any code outside libgss */
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
index 4bfe863f99..a1cd2b4a63 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -82,6 +82,12 @@ typedef struct {
gss_name_t mech_name;
} spnego_name_desc, *spnego_name_t;
+/* Structure for credential */
+typedef struct {
+ gss_cred_id_t mcred; /* mechglue union of obtainable creds */
+ gss_OID_set neg_mechs; /* app-specified list of allowable mechs */
+} spnego_gss_cred_id_rec, *spnego_gss_cred_id_t;
+
/* Structure for context handle */
typedef struct {
OM_uint32 magic_num;
@@ -539,6 +545,14 @@ spnego_gss_pseudo_random
gss_buffer_t prf_out
);
+OM_uint32
+spnego_gss_set_neg_mechs
+(
+ OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ const gss_OID_set mech_list
+);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 669b343d97..60fadd5e5b 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -103,6 +103,8 @@ static gss_OID_set get_mech_set(OM_uint32 *, unsigned char **, unsigned int);
static OM_uint32 get_req_flags(unsigned char **, OM_uint32, OM_uint32 *);
static OM_uint32 get_available_mechs(OM_uint32 *, gss_name_t,
gss_cred_usage_t, gss_cred_id_t *, gss_OID_set *);
+static OM_uint32 get_negotiable_mechs(OM_uint32 *, spnego_gss_cred_id_t,
+ gss_cred_usage_t, gss_OID_set *);
static void release_spnego_ctx(spnego_gss_ctx_id_t *);
static void check_spnego_options(spnego_gss_ctx_id_t);
static spnego_gss_ctx_id_t create_spnego_ctx(void);
@@ -119,7 +121,7 @@ handle_mic(OM_uint32 *, gss_buffer_t, int, spnego_gss_ctx_id_t,
gss_buffer_t *, OM_uint32 *, send_token_flag *);
static OM_uint32
-init_ctx_new(OM_uint32 *, gss_cred_id_t, gss_ctx_id_t *,
+init_ctx_new(OM_uint32 *, spnego_gss_cred_id_t, gss_ctx_id_t *,
gss_OID_set *, send_token_flag *);
static OM_uint32
init_ctx_nego(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32, gss_OID,
@@ -134,14 +136,14 @@ init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
gss_OID, gss_buffer_t *, gss_buffer_t *,
OM_uint32 *, send_token_flag *);
static OM_uint32
-init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
gss_OID *, gss_buffer_t, OM_uint32 *, OM_uint32 *,
OM_uint32 *, send_token_flag *);
static OM_uint32
acc_ctx_new(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
- gss_cred_id_t, gss_buffer_t *,
+ spnego_gss_cred_id_t, gss_buffer_t *,
gss_buffer_t *, OM_uint32 *, send_token_flag *);
static OM_uint32
acc_ctx_cont(OM_uint32 *, gss_buffer_t, gss_ctx_id_t *,
@@ -151,7 +153,7 @@ static OM_uint32
acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
OM_uint32 *, send_token_flag *);
static OM_uint32
-acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, gss_cred_id_t,
+acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
gss_buffer_t, gss_OID *, gss_buffer_t,
OM_uint32 *, OM_uint32 *, gss_cred_id_t *,
OM_uint32 *, send_token_flag *);
@@ -195,10 +197,10 @@ static const gss_OID_set_desc spnego_oidsets[] = {
};
const gss_OID_set_desc * const gss_mech_set_spnego = spnego_oidsets+0;
-static int make_NegHints(OM_uint32 *, gss_cred_id_t, gss_buffer_t *);
+static int make_NegHints(OM_uint32 *, spnego_gss_cred_id_t, gss_buffer_t *);
static int put_neg_hints(unsigned char **, gss_buffer_t, unsigned int);
static OM_uint32
-acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, gss_cred_id_t,
+acc_ctx_hints(OM_uint32 *, gss_ctx_id_t *, spnego_gss_cred_id_t,
gss_buffer_t *, OM_uint32 *, send_token_flag *);
/*
@@ -269,6 +271,7 @@ static struct gss_config spnego_mechanism =
spnego_gss_map_name_to_any,
spnego_gss_release_any_name_mapping,
spnego_gss_pseudo_random,
+ spnego_gss_set_neg_mechs,
};
#ifdef _GSS_STATIC_LINK
@@ -323,6 +326,8 @@ spnego_gss_acquire_cred(OM_uint32 *minor_status,
{
OM_uint32 status;
gss_OID_set amechs;
+ gss_cred_id_t mcred = NULL;
+ spnego_gss_cred_id_t spcred = NULL;
dsyslog("Entering spnego_gss_acquire_cred\n");
if (actual_mechs)
@@ -331,6 +336,13 @@ spnego_gss_acquire_cred(OM_uint32 *minor_status,
if (time_rec)
*time_rec = 0;
+ spcred = malloc(sizeof(spnego_gss_cred_id_rec));
+ if (spcred == NULL) {
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ spcred->neg_mechs = GSS_C_NULL_OID_SET;
+
/*
* If the user did not specify a list of mechs,
* use get_available_mechs to collect a list of
@@ -339,7 +351,7 @@ spnego_gss_acquire_cred(OM_uint32 *minor_status,
if (desired_mechs == GSS_C_NULL_OID_SET) {
status = get_available_mechs(minor_status,
desired_name, cred_usage,
- output_cred_handle, &amechs);
+ &mcred, &amechs);
} else {
/*
* The caller gave a specific list of mechanisms,
@@ -350,8 +362,7 @@ spnego_gss_acquire_cred(OM_uint32 *minor_status,
status = gss_acquire_cred(minor_status,
desired_name, time_req,
desired_mechs, cred_usage,
- output_cred_handle, &amechs,
- time_rec);
+ &mcred, &amechs, time_rec);
}
if (actual_mechs && amechs != GSS_C_NULL_OID_SET) {
@@ -359,6 +370,14 @@ spnego_gss_acquire_cred(OM_uint32 *minor_status,
}
(void) gss_release_oid_set(minor_status, &amechs);
+ if (status == GSS_S_COMPLETE) {
+ spcred->mcred = mcred;
+ *output_cred_handle = (gss_cred_id_t)spcred;
+ } else {
+ free(spcred);
+ *output_cred_handle = GSS_C_NO_CREDENTIAL;
+ }
+
dsyslog("Leaving spnego_gss_acquire_cred\n");
return (status);
}
@@ -368,7 +387,7 @@ OM_uint32
spnego_gss_release_cred(OM_uint32 *minor_status,
gss_cred_id_t *cred_handle)
{
- OM_uint32 status;
+ spnego_gss_cred_id_t spcred = NULL;
dsyslog("Entering spnego_gss_release_cred\n");
@@ -380,10 +399,14 @@ spnego_gss_release_cred(OM_uint32 *minor_status,
if (*cred_handle == GSS_C_NO_CREDENTIAL)
return (GSS_S_COMPLETE);
- status = gss_release_cred(minor_status, cred_handle);
+ spcred = (spnego_gss_cred_id_t)*cred_handle;
+ *cred_handle = GSS_C_NO_CREDENTIAL;
+ gss_release_oid_set(minor_status, &spcred->neg_mechs);
+ gss_release_cred(minor_status, &spcred->mcred);
+ free(spcred);
dsyslog("Leaving spnego_gss_release_cred\n");
- return (status);
+ return (GSS_S_COMPLETE);
}
static void
@@ -540,28 +563,17 @@ process_mic(OM_uint32 *minor_status, gss_buffer_t mic_in,
*/
static OM_uint32
init_ctx_new(OM_uint32 *minor_status,
- gss_cred_id_t cred,
+ spnego_gss_cred_id_t spcred,
gss_ctx_id_t *ctx,
gss_OID_set *mechSet,
send_token_flag *tokflag)
{
OM_uint32 ret, tmpmin;
- gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
spnego_gss_ctx_id_t sc = NULL;
/* determine negotiation mech set */
- if (cred == GSS_C_NO_CREDENTIAL) {
- ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
- GSS_C_INITIATE, &creds, mechSet);
- gss_release_cred(&tmpmin, &creds);
- } else {
- /*
- * Use the list of mechs included in the cred that we
- * were given.
- */
- ret = gss_inquire_cred(minor_status, cred,
- NULL, NULL, NULL, mechSet);
- }
+ ret = get_negotiable_mechs(minor_status, spcred, GSS_C_INITIATE,
+ mechSet);
if (ret != GSS_S_COMPLETE)
return ret;
@@ -795,7 +807,7 @@ init_ctx_reselect(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
static OM_uint32
init_ctx_call_init(OM_uint32 *minor_status,
spnego_gss_ctx_id_t sc,
- gss_cred_id_t claimant_cred_handle,
+ spnego_gss_cred_id_t spcred,
gss_name_t target_name,
OM_uint32 req_flags,
OM_uint32 time_req,
@@ -808,9 +820,11 @@ init_ctx_call_init(OM_uint32 *minor_status,
send_token_flag *send_token)
{
OM_uint32 ret;
+ gss_cred_id_t mcred;
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
ret = gss_init_sec_context(minor_status,
- claimant_cred_handle,
+ mcred,
&sc->ctx_handle,
target_name,
sc->internal_mech,
@@ -887,6 +901,7 @@ spnego_gss_init_sec_context(
gss_buffer_t mechtok_in, mechListMIC_in, mechListMIC_out;
gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
gss_OID_set mechSet = GSS_C_NO_OID_SET;
+ spnego_gss_cred_id_t spcred = NULL;
spnego_gss_ctx_id_t spnego_ctx = NULL;
dsyslog("Entering init_sec_context\n");
@@ -908,8 +923,9 @@ spnego_gss_init_sec_context(
if (actual_mech != NULL)
*actual_mech = GSS_C_NO_OID;
+ spcred = (spnego_gss_cred_id_t)claimant_cred_handle;
if (*context_handle == GSS_C_NO_CONTEXT) {
- ret = init_ctx_new(minor_status, claimant_cred_handle,
+ ret = init_ctx_new(minor_status, spcred,
context_handle, &mechSet, &send_token);
if (ret != GSS_S_CONTINUE_NEEDED) {
goto cleanup;
@@ -925,8 +941,7 @@ spnego_gss_init_sec_context(
spnego_ctx = (spnego_gss_ctx_id_t)*context_handle;
if (!spnego_ctx->mech_complete) {
ret = init_ctx_call_init(
- minor_status, spnego_ctx,
- claimant_cred_handle,
+ minor_status, spnego_ctx, spcred,
target_name, req_flags,
time_req, mechtok_in,
actual_mech, &mechtok_out,
@@ -1045,7 +1060,7 @@ put_neg_hints(unsigned char **buf_out, gss_buffer_t input_token,
static int
make_NegHints(OM_uint32 *minor_status,
- gss_cred_id_t cred, gss_buffer_t *outbuf)
+ spnego_gss_cred_id_t spcred, gss_buffer_t *outbuf)
{
gss_buffer_desc hintNameBuf;
gss_name_t hintName = GSS_C_NO_NAME;
@@ -1061,9 +1076,9 @@ make_NegHints(OM_uint32 *minor_status,
*outbuf = GSS_C_NO_BUFFER;
- if (cred != GSS_C_NO_CREDENTIAL) {
+ if (spcred != NULL) {
major_status = gss_inquire_cred(minor_status,
- cred,
+ spcred->mcred,
&hintName,
NULL,
NULL,
@@ -1188,7 +1203,7 @@ errout:
static OM_uint32
acc_ctx_hints(OM_uint32 *minor_status,
gss_ctx_id_t *ctx,
- gss_cred_id_t cred,
+ spnego_gss_cred_id_t spcred,
gss_buffer_t *mechListMIC,
OM_uint32 *negState,
send_token_flag *return_token)
@@ -1206,24 +1221,14 @@ acc_ctx_hints(OM_uint32 *minor_status,
*ctx = GSS_C_NO_CONTEXT;
ret = GSS_S_DEFECTIVE_TOKEN;
- if (cred != GSS_C_NO_CREDENTIAL) {
- ret = gss_inquire_cred(minor_status, cred, NULL, NULL,
- NULL, &supported_mechSet);
- if (ret != GSS_S_COMPLETE) {
- *return_token = NO_TOKEN_SEND;
- goto cleanup;
- }
- } else {
- ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
- GSS_C_ACCEPT, NULL,
- &supported_mechSet);
- if (ret != GSS_S_COMPLETE) {
- *return_token = NO_TOKEN_SEND;
- goto cleanup;
- }
+ ret = get_negotiable_mechs(minor_status, spcred, GSS_C_ACCEPT,
+ &supported_mechSet);
+ if (ret != GSS_S_COMPLETE) {
+ *return_token = NO_TOKEN_SEND;
+ goto cleanup;
}
- ret = make_NegHints(minor_status, cred, mechListMIC);
+ ret = make_NegHints(minor_status, spcred, mechListMIC);
if (ret != GSS_S_COMPLETE) {
*return_token = NO_TOKEN_SEND;
goto cleanup;
@@ -1268,7 +1273,7 @@ static OM_uint32
acc_ctx_new(OM_uint32 *minor_status,
gss_buffer_t buf,
gss_ctx_id_t *ctx,
- gss_cred_id_t cred,
+ spnego_gss_cred_id_t spcred,
gss_buffer_t *mechToken,
gss_buffer_t *mechListMIC,
OM_uint32 *negState,
@@ -1297,21 +1302,11 @@ acc_ctx_new(OM_uint32 *minor_status,
if (ret != GSS_S_COMPLETE) {
goto cleanup;
}
- if (cred != GSS_C_NO_CREDENTIAL) {
- ret = gss_inquire_cred(minor_status, cred, NULL, NULL,
- NULL, &supported_mechSet);
- if (ret != GSS_S_COMPLETE) {
- *return_token = NO_TOKEN_SEND;
- goto cleanup;
- }
- } else {
- ret = get_available_mechs(minor_status, GSS_C_NO_NAME,
- GSS_C_ACCEPT, NULL,
- &supported_mechSet);
- if (ret != GSS_S_COMPLETE) {
- *return_token = NO_TOKEN_SEND;
- goto cleanup;
- }
+ ret = get_negotiable_mechs(minor_status, spcred, GSS_C_ACCEPT,
+ &supported_mechSet);
+ if (ret != GSS_S_COMPLETE) {
+ *return_token = NO_TOKEN_SEND;
+ goto cleanup;
}
/*
* Select the best match between the list of mechs
@@ -1484,7 +1479,7 @@ cleanup:
*/
static OM_uint32
acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
- gss_cred_id_t cred, gss_buffer_t mechtok_in,
+ spnego_gss_cred_id_t spcred, gss_buffer_t mechtok_in,
gss_OID *mech_type, gss_buffer_t mechtok_out,
OM_uint32 *ret_flags, OM_uint32 *time_rec,
gss_cred_id_t *delegated_cred_handle,
@@ -1492,6 +1487,7 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
{
OM_uint32 ret;
gss_OID_desc mechoid;
+ gss_cred_id_t mcred;
if (sc->ctx_handle == GSS_C_NO_CONTEXT) {
/*
@@ -1508,9 +1504,10 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
return ret;
}
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
ret = gss_accept_sec_context(minor_status,
&sc->ctx_handle,
- cred,
+ mcred,
mechtok_in,
GSS_C_NO_CHANNEL_BINDINGS,
&sc->internal_name,
@@ -1571,6 +1568,7 @@ spnego_gss_accept_sec_context(
gss_buffer_t mechtok_in, mic_in, mic_out;
gss_buffer_desc mechtok_out = GSS_C_EMPTY_BUFFER;
spnego_gss_ctx_id_t sc = NULL;
+ spnego_gss_cred_id_t spcred = NULL;
OM_uint32 mechstat = GSS_S_FAILURE;
int sendTokenInit = 0;
@@ -1592,6 +1590,7 @@ spnego_gss_accept_sec_context(
return GSS_S_CALL_INACCESSIBLE_READ;
sc = (spnego_gss_ctx_id_t)*context_handle;
+ spcred = (spnego_gss_cred_id_t)verifier_cred_handle;
if (sc == NULL || sc->internal_mech == GSS_C_NO_OID) {
if (src_name != NULL)
*src_name = GSS_C_NO_NAME;
@@ -1606,8 +1605,7 @@ spnego_gss_accept_sec_context(
if (input_token->length == 0) {
sendTokenInit = 1;
ret = acc_ctx_hints(minor_status,
- context_handle,
- verifier_cred_handle,
+ context_handle, spcred,
&mic_out,
&negState,
&return_token);
@@ -1617,7 +1615,7 @@ spnego_gss_accept_sec_context(
} else {
/* Can set negState to REQUEST_MIC */
ret = acc_ctx_new(minor_status, input_token,
- context_handle, verifier_cred_handle,
+ context_handle, spcred,
&mechtok_in, &mic_in,
&negState, &return_token);
if (ret != GSS_S_COMPLETE)
@@ -1643,9 +1641,8 @@ spnego_gss_accept_sec_context(
*/
mechstat = GSS_S_FAILURE;
if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
- ret = acc_ctx_call_acc(minor_status, sc,
- verifier_cred_handle, mechtok_in,
- mech_type, &mechtok_out,
+ ret = acc_ctx_call_acc(minor_status, sc, spcred,
+ mechtok_in, mech_type, &mechtok_out,
ret_flags, time_rec,
delegated_cred_handle,
&negState, &return_token);
@@ -1808,6 +1805,7 @@ spnego_gss_inquire_cred(
gss_OID_set *mechanisms)
{
OM_uint32 status;
+ spnego_gss_cred_id_t spcred = NULL;
gss_cred_id_t creds = GSS_C_NO_CREDENTIAL;
OM_uint32 tmp_minor_status;
OM_uint32 initiator_lifetime, acceptor_lifetime;
@@ -1819,7 +1817,8 @@ spnego_gss_inquire_cred(
* supplied we call gss_inquire_cred_by_mech() on the
* first non-SPNEGO mechanism.
*/
- if (cred_handle == GSS_C_NO_CREDENTIAL) {
+ spcred = (spnego_gss_cred_id_t)cred_handle;
+ if (spcred == NULL) {
status = get_available_mechs(minor_status,
GSS_C_NO_NAME,
GSS_C_BOTH,
@@ -1858,7 +1857,7 @@ spnego_gss_inquire_cred(
gss_release_cred(&tmp_minor_status, &creds);
} else {
- status = gss_inquire_cred(minor_status, cred_handle,
+ status = gss_inquire_cred(minor_status, spcred->mcred,
name, lifetime,
cred_usage, mechanisms);
}
@@ -2179,8 +2178,11 @@ spnego_gss_inquire_cred_by_oid(
gss_buffer_set_t *data_set)
{
OM_uint32 ret;
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)cred_handle;
+ gss_cred_id_t mcred;
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
ret = gss_inquire_cred_by_oid(minor_status,
- cred_handle,
+ mcred,
desired_object,
data_set);
return (ret);
@@ -2194,8 +2196,11 @@ spnego_gss_set_cred_option(
const gss_buffer_t value)
{
OM_uint32 ret;
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)cred_handle;
+ gss_cred_id_t mcred;
+ mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
ret = gssspi_set_cred_option(minor_status,
- cred_handle,
+ mcred,
desired_object,
value);
return (ret);
@@ -2344,6 +2349,8 @@ spnego_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
{
OM_uint32 status;
gss_OID_set amechs = GSS_C_NULL_OID_SET;
+ spnego_gss_cred_id_t imp_spcred = NULL, out_spcred = NULL;
+ gss_cred_id_t mcred;
dsyslog("Entering spnego_gss_acquire_cred_impersonate_name\n");
@@ -2364,16 +2371,27 @@ spnego_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
desired_mechs = amechs;
}
+ imp_spcred = (spnego_gss_cred_id_t)impersonator_cred_handle;
status = gss_acquire_cred_impersonate_name(minor_status,
- impersonator_cred_handle,
+ imp_spcred ? imp_spcred->mcred : GSS_C_NO_CREDENTIAL,
desired_name, time_req,
desired_mechs, cred_usage,
- output_cred_handle, actual_mechs,
+ &mcred, actual_mechs,
time_rec);
if (amechs != GSS_C_NULL_OID_SET)
(void) gss_release_oid_set(minor_status, &amechs);
+ out_spcred = malloc(sizeof(spnego_gss_cred_id_rec));
+ if (out_spcred == NULL) {
+ gss_release_cred(minor_status, &mcred);
+ *minor_status = ENOMEM;
+ return (GSS_S_FAILURE);
+ }
+ out_spcred->mcred = mcred;
+ out_spcred->neg_mechs = GSS_C_NULL_OID_SET;
+ *output_cred_handle = (gss_cred_id_t)out_spcred;
+
dsyslog("Leaving spnego_gss_acquire_cred_impersonate_name\n");
return (status);
}
@@ -2519,6 +2537,21 @@ spnego_gss_pseudo_random(OM_uint32 *minor_status,
return (ret);
}
+OM_uint32
+spnego_gss_set_neg_mechs(OM_uint32 *minor_status,
+ gss_cred_id_t cred_handle,
+ const gss_OID_set mech_list)
+{
+ OM_uint32 ret;
+ spnego_gss_cred_id_t spcred = (spnego_gss_cred_id_t)cred_handle;
+
+ /* Store mech_list in spcred for use in negotiation logic. */
+ gss_release_oid_set(minor_status, &spcred->neg_mechs);
+ ret = generic_gss_copy_oid_set(minor_status, mech_list,
+ &spcred->neg_mechs);
+ return (ret);
+}
+
/*
* We will release everything but the ctx_handle so that it
* can be passed back to init/accept context. This routine should
@@ -2632,6 +2665,83 @@ get_available_mechs(OM_uint32 *minor_status,
return (major_status);
}
+/*
+ * Return a list of mechanisms we are willing to negotiate for a credential,
+ * taking into account the mech set provided with gss_set_neg_mechs if it
+ * exists.
+ */
+static OM_uint32
+get_negotiable_mechs(OM_uint32 *minor_status, spnego_gss_cred_id_t spcred,
+ gss_cred_usage_t usage, gss_OID_set *rmechs)
+{
+ OM_uint32 ret, tmpmin;
+ gss_cred_id_t creds = GSS_C_NO_CREDENTIAL, *credptr;
+ gss_OID_set cred_mechs = GSS_C_NULL_OID_SET;
+ gss_OID_set intersect_mechs = GSS_C_NULL_OID_SET;
+ unsigned int i, j;
+
+ if (spcred == NULL) {
+ /*
+ * The default credentials were supplied. Return a list of all
+ * available mechs except SPNEGO. When initiating, trim this
+ * list to mechs we can acquire credentials for.
+ */
+ credptr = (usage == GSS_C_INITIATE) ? &creds : NULL;
+ ret = get_available_mechs(minor_status, GSS_C_NO_NAME, usage,
+ credptr, rmechs);
+ gss_release_cred(&tmpmin, &creds);
+ return (ret);
+ }
+
+ /* Get the list of mechs in the mechglue cred. */
+ ret = gss_inquire_cred(minor_status, spcred->mcred, NULL, NULL, NULL,
+ &cred_mechs);
+ if (ret != GSS_S_COMPLETE)
+ return (ret);
+
+ if (spcred->neg_mechs == GSS_C_NULL_OID_SET) {
+ /* gss_set_neg_mechs was never called; return cred_mechs. */
+ *rmechs = cred_mechs;
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+ }
+
+ /* Compute the intersection of cred_mechs and spcred->neg_mechs,
+ * preserving the order in spcred->neg_mechs. */
+ ret = gss_create_empty_oid_set(minor_status, &intersect_mechs);
+ if (ret != GSS_S_COMPLETE) {
+ gss_release_oid_set(&tmpmin, &cred_mechs);
+ return (ret);
+ }
+
+ for (i = 0; i < spcred->neg_mechs->count; i++) {
+ for (j = 0; j < cred_mechs->count; j++) {
+ if (!g_OID_equal(&spcred->neg_mechs->elements[i],
+ &cred_mechs->elements[j]))
+ break;
+ }
+ if (j == cred_mechs->count)
+ continue;
+ ret = gss_add_oid_set_member(minor_status,
+ &spcred->neg_mechs->elements[i],
+ &intersect_mechs);
+ if (ret != GSS_S_COMPLETE)
+ break;
+ }
+
+ gss_release_oid_set(&tmpmin, &cred_mechs);
+ if (intersect_mechs->count == 0 || ret != GSS_S_COMPLETE) {
+ gss_release_oid_set(&tmpmin, &intersect_mechs);
+ *minor_status = ERR_SPNEGO_NO_MECHS_AVAILABLE;
+ map_errcode(minor_status);
+ return (GSS_S_FAILURE);
+ }
+
+ *rmechs = intersect_mechs;
+ *minor_status = 0;
+ return (GSS_S_COMPLETE);
+}
+
/* following are token creation and reading routines */
/*