svn rev #23715: trunk/src/ lib/gssapi/ lib/gssapi/generic/ lib/gssapi/krb5/ lib/gssapi/mechglue/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Wed Feb 10 18:44:18 EST 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=23715
Commit By: ghudson
Log Message:
ticket: 6658
subject: Implement gss_set_neg_mechs
target_version: 1.8
tags: pullup

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.



Changed Files:
U   trunk/src/lib/gssapi/generic/gssapi.hin
U   trunk/src/lib/gssapi/krb5/gssapi_krb5.c
U   trunk/src/lib/gssapi/libgssapi_krb5.exports
U   trunk/src/lib/gssapi/mechglue/Makefile.in
U   trunk/src/lib/gssapi/mechglue/g_initialize.c
A   trunk/src/lib/gssapi/mechglue/g_set_neg_mechs.c
U   trunk/src/lib/gssapi/mechglue/mglueP.h
U   trunk/src/lib/gssapi/spnego/gssapiP_spnego.h
U   trunk/src/lib/gssapi/spnego/spnego_mech.c
U   trunk/src/tests/gssapi/Makefile.in
A   trunk/src/tests/gssapi/t_spnego.c
Modified: trunk/src/lib/gssapi/generic/gssapi.hin
===================================================================
--- trunk/src/lib/gssapi/generic/gssapi.hin	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/generic/gssapi.hin	2010-02-10 23:44:18 UTC (rev 23715)
@@ -805,6 +805,12 @@
     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

Modified: trunk/src/lib/gssapi/krb5/gssapi_krb5.c
===================================================================
--- trunk/src/lib/gssapi/krb5/gssapi_krb5.c	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/krb5/gssapi_krb5.c	2010-02-10 23:44:18 UTC (rev 23715)
@@ -694,6 +694,7 @@
     krb5_gss_map_name_to_any,
     krb5_gss_release_any_name_mapping,
     krb5_gss_pseudo_random,
+    NULL,               /* set_neg_mechs */
 };
 
 

Modified: trunk/src/lib/gssapi/libgssapi_krb5.exports
===================================================================
--- trunk/src/lib/gssapi/libgssapi_krb5.exports	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/libgssapi_krb5.exports	2010-02-10 23:44:18 UTC (rev 23715)
@@ -80,6 +80,7 @@
 gss_release_oid_set
 gss_seal
 gss_set_name_attribute
+gss_set_neg_mechs
 gss_set_sec_context_option
 gss_sign
 gss_store_cred

Modified: trunk/src/lib/gssapi/mechglue/Makefile.in
===================================================================
--- trunk/src/lib/gssapi/mechglue/Makefile.in	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/mechglue/Makefile.in	2010-02-10 23:44:18 UTC (rev 23715)
@@ -54,6 +54,7 @@
 	$(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 @@
 	$(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 @@
 	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 \

Modified: trunk/src/lib/gssapi/mechglue/g_initialize.c
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_initialize.c	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/mechglue/g_initialize.c	2010-02-10 23:44:18 UTC (rev 23715)
@@ -775,6 +775,8 @@
 	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);
 

Added: trunk/src/lib/gssapi/mechglue/g_set_neg_mechs.c
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_set_neg_mechs.c	                        (rev 0)
+++ trunk/src/lib/gssapi/mechglue/g_set_neg_mechs.c	2010-02-10 23:44:18 UTC (rev 23715)
@@ -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;
+}

Modified: trunk/src/lib/gssapi/mechglue/mglueP.h
===================================================================
--- trunk/src/lib/gssapi/mechglue/mglueP.h	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/mechglue/mglueP.h	2010-02-10 23:44:18 UTC (rev 23715)
@@ -583,6 +583,12 @@
             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 */

Modified: trunk/src/lib/gssapi/spnego/gssapiP_spnego.h
===================================================================
--- trunk/src/lib/gssapi/spnego/gssapiP_spnego.h	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/spnego/gssapiP_spnego.h	2010-02-10 23:44:18 UTC (rev 23715)
@@ -82,6 +82,12 @@
 	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 @@
 	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

Modified: trunk/src/lib/gssapi/spnego/spnego_mech.c
===================================================================
--- trunk/src/lib/gssapi/spnego/spnego_mech.c	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/lib/gssapi/spnego/spnego_mech.c	2010-02-10 23:44:18 UTC (rev 23715)
@@ -103,6 +103,8 @@
 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 @@
 	   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 @@
 		  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 @@
 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 @@
 };
 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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	}
 	(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 @@
 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 @@
 	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 @@
  */
 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 @@
 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 @@
 		   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 @@
 	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 @@
 	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_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 @@
 
 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 @@
 
 	*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 @@
 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 @@
 	*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 @@
 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 @@
 	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 @@
  */
 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 @@
 {
 	OM_uint32 ret;
 	gss_OID_desc mechoid;
+	gss_cred_id_t mcred;
 
 	if (sc->ctx_handle == GSS_C_NO_CONTEXT) {
 		/*
@@ -1508,9 +1504,10 @@
 			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 @@
 	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 @@
 		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 @@
 		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 @@
 		} 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 @@
 	 */
 	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 @@
 			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 @@
 	 * 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 @@
 
 		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 @@
 		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 @@
 		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 @@
 {
 	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 @@
 		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 @@
         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 @@
 	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 */
 
 /*

Modified: trunk/src/tests/gssapi/Makefile.in
===================================================================
--- trunk/src/tests/gssapi/Makefile.in	2010-02-10 01:55:36 UTC (rev 23714)
+++ trunk/src/tests/gssapi/Makefile.in	2010-02-10 23:44:18 UTC (rev 23715)
@@ -8,7 +8,7 @@
 
 OBJS= t_imp_name.o t_s4u.o t_namingexts.o t_gssexts.o
 
-all:: t_imp_name t_s4u t_namingexts t_gssexts
+all:: t_imp_name t_s4u t_namingexts t_gssexts t_spnego
 
 t_imp_name: t_imp_name.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_imp_name t_imp_name.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
@@ -18,7 +18,9 @@
 	$(CC_LINK) -o t_namingexts t_namingexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 t_gssexts: t_gssexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_gssexts t_gssexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+t_spnego: t_spnego.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_spnego t_spnego.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 
 clean::
-	$(RM) t_imp_name t_s4u t_namingexts t_gssexts
+	$(RM) t_imp_name t_s4u t_namingexts t_gssexts t_spnego
 

Added: trunk/src/tests/gssapi/t_spnego.c
===================================================================
--- trunk/src/tests/gssapi/t_spnego.c	                        (rev 0)
+++ trunk/src/tests/gssapi/t_spnego.c	2010-02-10 23:44:18 UTC (rev 23715)
@@ -0,0 +1,265 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gssapi/gssapi_krb5.h>
+
+/*
+ * Test program for SPNEGO and gss_set_neg_mechs
+ *
+ * Example usage:
+ *
+ * kinit testuser
+ * ./t_spnego host/test.host at REALM testhost.keytab
+ */
+
+static gss_OID_desc spnego_mech = { 6, "\053\006\001\005\005\002" };
+
+static void displayStatus_1(m, code, type)
+     char *m;
+     OM_uint32 code;
+     int type;
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+
+     msg_ctx = 0;
+     while (1) {
+          maj_stat = gss_display_status(&min_stat, code,
+                                       type, GSS_C_NULL_OID,
+                                       &msg_ctx, &msg);
+          fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
+          (void) gss_release_buffer(&min_stat, &msg);
+
+          if (!msg_ctx)
+               break;
+     }
+}
+
+static void displayStatus(msg, maj_stat, min_stat)
+     char *msg;
+     OM_uint32 maj_stat;
+     OM_uint32 min_stat;
+{
+     displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
+     displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static OM_uint32
+displayCanonName(OM_uint32 *minor, gss_name_t name, char *tag)
+{
+    gss_name_t canon;
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc buf;
+
+    major = gss_canonicalize_name(minor, name,
+                                  (gss_OID)gss_mech_krb5, &canon);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_canonicalize_name", major, *minor);
+        return major;
+    }
+
+    major = gss_display_name(minor, canon, &buf, NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_display_name", major, *minor);
+        gss_release_name(&tmp_minor, &canon);
+        return major;
+    }
+
+    printf("%s:\t%s\n", tag, (char *)buf.value);
+
+    gss_release_buffer(&tmp_minor, &buf);
+    gss_release_name(&tmp_minor, &canon);
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+displayOID(OM_uint32 *minor, gss_OID oid, char *tag)
+{
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc buf;
+
+    major = gss_oid_to_str(minor, oid, &buf);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_oid_to_str", major, *minor);
+        return major;
+    }
+
+    printf("%s:\t%s\n", tag, (char *)buf.value);
+
+    gss_release_buffer(&tmp_minor, &buf);
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+initAcceptSecContext(OM_uint32 *minor,
+		     gss_name_t target_name,
+                     gss_cred_id_t verifier_cred_handle)
+{
+    OM_uint32 major;
+    gss_buffer_desc token, tmp;
+    gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+    gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
+    gss_name_t source_name = GSS_C_NO_NAME;
+    OM_uint32 time_rec;
+    gss_OID mech = GSS_C_NO_OID;
+
+    token.value = NULL;
+    token.length = 0;
+
+    tmp.value = NULL;
+    tmp.length = 0;
+
+    major = gss_init_sec_context(minor,
+                                 GSS_C_NO_CREDENTIAL,
+                                 &initiator_context,
+                                 target_name,
+                                 &spnego_mech,
+                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+                                 GSS_C_INDEFINITE,
+                                 GSS_C_NO_CHANNEL_BINDINGS,
+                                 GSS_C_NO_BUFFER,
+                                 NULL,
+                                 &token,
+                                 NULL,
+                                 &time_rec);
+
+    if (target_name != GSS_C_NO_NAME)
+        (void) gss_release_name(minor, &target_name);
+
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_init_sec_context", major, *minor);
+        return major;
+    }
+
+    (void) gss_delete_sec_context(minor, &initiator_context, NULL);
+
+    major = gss_accept_sec_context(minor,
+                                   &acceptor_context,
+                                   verifier_cred_handle,
+                                   &token,
+                                   GSS_C_NO_CHANNEL_BINDINGS,
+                                   &source_name,
+                                   &mech,
+                                   &tmp,
+                                   NULL,
+                                   &time_rec,
+                                   NULL);
+
+    if (GSS_ERROR(major))
+        displayStatus("gss_accept_sec_context", major, *minor);
+    else {
+        displayCanonName(minor, source_name, "Source name");
+        displayOID(minor, mech, "Source mech");
+    }
+
+    (void) gss_release_name(minor, &source_name);
+    (void) gss_delete_sec_context(minor, &acceptor_context, NULL);
+    (void) gss_release_buffer(minor, &token);
+    (void) gss_release_buffer(minor, &tmp);
+    (void) gss_release_oid(minor, &mech);
+
+    return major;
+}
+
+int main(int argc, char *argv[])
+{
+    OM_uint32 minor, major;
+    gss_cred_id_t verifier_cred_handle = GSS_C_NO_CREDENTIAL;
+    gss_OID_set_desc mechs;
+    gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
+    gss_buffer_desc buf;
+    gss_name_t target_name;
+
+    if (argc < 2 || argc > 3) {
+        fprintf(stderr, "Usage: %s target_name [keytab]\n", argv[0]);
+        exit(1);
+    }
+
+    buf.value = argv[1];
+    buf.length = strlen((char *)buf.value);
+    major = gss_import_name(&minor, &buf,
+                            (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+                            &target_name);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_import_name(target_name)", major, minor);
+        goto out;
+    }
+
+    if (argc > 2) {
+        major = krb5_gss_register_acceptor_identity(argv[2]);
+        if (GSS_ERROR(major)) {
+            displayStatus("krb5_gss_register_acceptor_identity",
+                          major, minor);
+            goto out;
+        }
+    }
+
+    mechs.elements = &spnego_mech;
+    mechs.count = 1;
+
+    /* get default acceptor cred */
+    major = gss_acquire_cred(&minor,
+                             GSS_C_NO_NAME,
+                             GSS_C_INDEFINITE,
+                             &mechs,
+                             GSS_C_ACCEPT,
+                             &verifier_cred_handle,
+                             &actual_mechs,
+                             NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_acquire_cred", major, minor);
+        goto out;
+    }
+
+    /* Restrict the acceptor to krb5, to exercise the neg_mechs logic. */
+    mechs.elements = (gss_OID)gss_mech_krb5;
+    mechs.count = 1;
+    major = gss_set_neg_mechs(&minor, verifier_cred_handle, &mechs);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_set_neg_mechs", major, minor);
+        goto out;
+    }
+
+    major = initAcceptSecContext(&minor, target_name, verifier_cred_handle);
+    if (GSS_ERROR(major))
+        goto out;
+
+    printf("\n");
+
+out:
+    (void) gss_release_cred(&minor, &verifier_cred_handle);
+    (void) gss_release_oid_set(&minor, &actual_mechs);
+    (void) gss_release_name(&minor, &target_name);
+
+    return GSS_ERROR(major) ? 1 : 0;
+}




More information about the cvs-krb5 mailing list