[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

GSS extension implementation for Heimdal



Hello all, 
I've implemented part (hope the most important) of the GSS-API Extension
draft issued by the Global Grid Forum (take a look at
http://www.gridforum.org/2_SEC/GSI.htm --> GSS-API Extensions). The
implementation can be found in attachament (it's based om Heimdal 0.4e).

The implementation contains functions addressing credential handling
(gss_export_cred(), gss_import_cred()) and delegation on demand
(gss_init_delegation() and gss_accept_delegation()). Usage of these functions
can be found in testing examples, which are part of the patch. The patch also 
contains some bugfixes for Heimdal implementation of GSS-API.

regards

--
Dan
Index: heimdal/appl/test/gssapi_client.c
diff -u heimdal/appl/test/gssapi_client.c:1.1.1.1 heimdal/appl/test/gssapi_client.c:1.1.1.1.4.1
--- heimdal/appl/test/gssapi_client.c:1.1.1.1	Tue Feb 26 15:42:03 2002
+++ heimdal/appl/test/gssapi_client.c	Fri Aug 16 12:45:41 2002
@@ -40,9 +40,34 @@
 do_trans (int sock, gss_ctx_id_t context_hdl)
 {
     OM_uint32 maj_stat, min_stat;
-    gss_buffer_desc real_input_token, real_output_token;
+    gss_buffer_desc real_input_token = GSS_C_EMPTY_BUFFER, real_output_token;
     gss_buffer_t input_token = &real_input_token,
-	output_token = &real_output_token;
+    output_token = &real_output_token;
+    int delegation_done = 0;
+
+    /* First try delegating credentials */
+    while (!delegation_done) {
+       maj_stat = gss_init_delegation(&min_stat,
+	     			      context_hdl,
+	                              GSS_C_NO_CREDENTIAL,
+				      GSS_C_NO_OID,
+				      GSS_C_NO_OID_SET,
+				      NULL,
+				      input_token,
+				      0,
+				      output_token);
+       if (GSS_ERROR(maj_stat))
+	  gss_err (1, min_stat, "gss_init_sec_context()");
+       if (output_token->length != 0) {
+	  write_token (sock, output_token);
+	  gss_release_buffer(&min_stat, output_token);
+       }
+
+       if (maj_stat & GSS_S_CONTINUE_NEEDED)
+	  read_token (sock, input_token);
+       else
+	  delegation_done = 1;
+    }
 
     /* get_mic */
 
Index: heimdal/appl/test/gssapi_server.c
diff -u heimdal/appl/test/gssapi_server.c:1.1.1.1 heimdal/appl/test/gssapi_server.c:1.1.1.1.4.1
--- heimdal/appl/test/gssapi_server.c:1.1.1.1	Tue Feb 26 15:42:03 2002
+++ heimdal/appl/test/gssapi_server.c	Fri Aug 16 12:45:41 2002
@@ -46,7 +46,11 @@
     gss_buffer_desc name_token;
     gss_buffer_desc real_input_token, real_output_token;
     gss_buffer_t input_token = &real_input_token,
-	output_token = &real_output_token;
+    output_token = &real_output_token;
+    gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+
+
 
     maj_stat = gss_display_name (&min_stat,
 				 client_name,
@@ -59,6 +63,48 @@
 	    (char *)name_token.value);
 
     gss_release_buffer (&min_stat, &name_token);
+    
+    do {
+       read_token (sock, input_token);
+       maj_stat = gss_accept_delegation(&min_stat,
+					context_hdl,
+					GSS_C_NO_OID_SET,
+					NULL,
+					input_token,
+					0,
+					0,
+					&delegated_cred_handle,
+					NULL,
+					output_token);
+       if (GSS_ERROR(maj_stat))
+	  gss_err (1, min_stat, "gss_accept_delegation()");
+       if (output_token->length != 0) {
+	  write_token (sock, output_token);
+	  gss_release_buffer(&min_stat, output_token);
+       }
+    } while(maj_stat & GSS_S_CONTINUE_NEEDED);
+
+    {
+       gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER;
+       gss_cred_id_t creds;
+
+       maj_stat = gss_export_cred(&min_stat, delegated_cred_handle,
+				  GSS_C_NO_OID, 0, &export_cred);
+       if (GSS_ERROR(maj_stat))
+	  gss_err (1, min_stat, "gss_export_cred()");
+
+       maj_stat = gss_import_cred(&min_stat, &creds, GSS_C_NO_OID, 0,
+	                          &export_cred, 0, NULL);
+       if (GSS_ERROR(maj_stat))
+	  gss_err (1, min_stat, "gss_import_creds()");
+
+       memset(&export_cred, 0, sizeof(export_cred));
+       maj_stat = gss_export_cred(&min_stat, creds, GSS_C_NO_OID,
+	                          1, &export_cred);
+       if (GSS_ERROR(maj_stat))
+	  gss_err (1, min_stat, "gss_export_cred()");
+    }
+    
 
     /* gss_verify_mic */
 
@@ -113,8 +159,10 @@
     OM_uint32 maj_stat, min_stat;
     gss_name_t client_name;
     struct gss_channel_bindings_struct input_chan_bindings;
+    /*
     gss_cred_id_t delegated_cred_handle = NULL;
     krb5_ccache ccache;
+    */
     u_char init_buf[4];
     u_char acct_buf[4];
 
@@ -156,8 +204,10 @@
     input_chan_bindings.application_data.value = NULL;
 #endif
     
+    /*
     delegated_cred_handle = emalloc(sizeof(*delegated_cred_handle));
     memset((char*)delegated_cred_handle, 0, sizeof(*delegated_cred_handle));
+    */
     
     do {
 	read_token (sock, input_token);
@@ -186,6 +236,7 @@
 	}
     } while(maj_stat & GSS_S_CONTINUE_NEEDED);
     
+#if 0
     if (delegated_cred_handle->ccache) {
        krb5_context context;
 
@@ -196,6 +247,7 @@
        krb5_cc_close(context, ccache);
        krb5_cc_destroy(context, delegated_cred_handle->ccache);
     }
+#endif
 
     if (fork_flag) {
 	pid_t pid;
Index: heimdal/lib/gssapi/Makefile.am
diff -u heimdal/lib/gssapi/Makefile.am:1.1.1.1 heimdal/lib/gssapi/Makefile.am:1.1.1.1.2.2
--- heimdal/lib/gssapi/Makefile.am:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/Makefile.am	Mon Aug 12 14:20:29 2002
@@ -12,6 +12,7 @@
 
 libgssapi_la_SOURCES =		\
 	8003.c			\
+	accept_delegation.c	\
 	accept_sec_context.c	\
 	acquire_cred.c		\
 	add_oid_set_member.c	\
@@ -26,19 +27,23 @@
 	display_status.c	\
 	duplicate_name.c	\
 	encapsulate.c		\
+	export_cred.c		\
 	export_sec_context.c	\
 	export_name.c		\
 	external.c		\
 	get_mic.c		\
 	gssapi.h		\
 	gssapi_locl.h		\
+	import_cred.c		\
 	import_name.c		\
 	import_sec_context.c	\
 	indicate_mechs.c	\
 	init.c			\
+	init_delegation.c	\
 	init_sec_context.c	\
 	inquire_context.c	\
 	inquire_cred.c		\
+	padding.c		\
 	release_buffer.c	\
 	release_cred.c		\
 	release_name.c		\
Index: heimdal/lib/gssapi/Makefile.in
diff -u heimdal/lib/gssapi/Makefile.in:1.1.1.1 heimdal/lib/gssapi/Makefile.in:1.1.1.1.2.3
--- heimdal/lib/gssapi/Makefile.in:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/Makefile.in	Mon Aug 12 14:20:29 2002
@@ -207,6 +207,7 @@
 
 libgssapi_la_SOURCES = \
 	8003.c			\
+	accept_delegation.c	\
 	accept_sec_context.c	\
 	acquire_cred.c		\
 	add_oid_set_member.c	\
@@ -221,19 +222,23 @@
 	display_status.c	\
 	duplicate_name.c	\
 	encapsulate.c		\
+	export_cred.c		\
 	export_sec_context.c	\
 	export_name.c		\
 	external.c		\
 	get_mic.c		\
 	gssapi.h		\
 	gssapi_locl.h		\
+	import_cred.c		\
 	import_name.c		\
 	import_sec_context.c	\
 	indicate_mechs.c	\
 	init.c			\
+	init_delegation.c	\
 	init_sec_context.c	\
 	inquire_context.c	\
 	inquire_cred.c		\
+	padding.c		\
 	release_buffer.c	\
 	release_cred.c		\
 	release_name.c		\
@@ -261,16 +266,17 @@
 X_PRE_LIBS = @X_PRE_LIBS@
 libgssapi_la_DEPENDENCIES =  ../krb5/libkrb5.la ../asn1/libasn1.la \
 ../roken/libroken.la
-am_libgssapi_la_OBJECTS =  8003.lo accept_sec_context.lo acquire_cred.lo \
-add_oid_set_member.lo canonicalize_name.lo compare_name.lo \
-context_time.lo copy_ccache.lo create_emtpy_oid_set.lo decapsulate.lo \
-delete_sec_context.lo display_name.lo display_status.lo \
-duplicate_name.lo encapsulate.lo export_sec_context.lo export_name.lo \
-external.lo get_mic.lo import_name.lo import_sec_context.lo \
-indicate_mechs.lo init.lo init_sec_context.lo inquire_context.lo \
-inquire_cred.lo release_buffer.lo release_cred.lo release_name.lo \
-release_oid_set.lo test_oid_set_member.lo unwrap.lo v1.lo verify_mic.lo \
-wrap.lo address_to_krb5addr.lo
+am_libgssapi_la_OBJECTS =  8003.lo accept_delegation.lo \
+accept_sec_context.lo acquire_cred.lo add_oid_set_member.lo \
+canonicalize_name.lo compare_name.lo context_time.lo copy_ccache.lo \
+create_emtpy_oid_set.lo decapsulate.lo delete_sec_context.lo \
+display_name.lo display_status.lo duplicate_name.lo encapsulate.lo \
+export_cred.lo export_sec_context.lo export_name.lo external.lo \
+get_mic.lo import_cred.lo import_name.lo import_sec_context.lo \
+indicate_mechs.lo init.lo init_delegation.lo init_sec_context.lo \
+inquire_context.lo inquire_cred.lo padding.lo release_buffer.lo \
+release_cred.lo release_name.lo release_oid_set.lo test_oid_set_member.lo \
+unwrap.lo v1.lo verify_mic.lo wrap.lo address_to_krb5addr.lo
 libgssapi_la_OBJECTS =  $(am_libgssapi_la_OBJECTS)
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
Index: heimdal/lib/gssapi/accept_delegation.c
diff -u /dev/null heimdal/lib/gssapi/accept_delegation.c:1.1.2.1
--- /dev/null	Sun Aug 18 17:18:27 2002
+++ heimdal/lib/gssapi/accept_delegation.c	Mon Aug 12 13:11:31 2002
@@ -0,0 +1,51 @@
+#include "gssapi_locl.h"
+
+RCSID("$Id$");
+
+OM_uint32
+gss_accept_delegation(
+        OM_uint32 *            minor_status,
+        const gss_ctx_id_t     context_handle,
+        const gss_OID_set      extension_oids,
+        const gss_buffer_set_t extension_buffers,
+        const gss_buffer_t     input_token,
+        OM_uint32              time_req,
+        OM_uint32 *            time_rec,
+        gss_cred_id_t *        delegated_cred_handle,
+        gss_OID *              mech_type,
+        gss_buffer_t           output_token)
+{
+   OM_uint32 ret;
+   krb5_data fwd_data;
+
+   krb5_data_zero(&fwd_data);
+
+   gssapi_krb5_init ();
+   *minor_status = 0;
+
+   if (context_handle == GSS_C_NO_CONTEXT)
+      return GSS_S_FAILURE;
+
+   if (input_token == GSS_C_NO_BUFFER || input_token->length <= 0)
+      return GSS_S_DEFECTIVE_TOKEN;
+
+   if (delegated_cred_handle == NULL)
+      return GSS_S_FAILURE;
+
+   ret = gssapi_krb5_decapsulate(minor_status, input_token, &fwd_data,
+	 			 "\x05\x01");
+   if (ret)
+      return ret;
+
+   if (fwd_data.length <= 0)
+      return GSS_S_DEFECTIVE_TOKEN;
+
+   ret = gssapi_krb5_rd_delegation(minor_status,
+	 			   gssapi_krb5_context,
+				   context_handle->auth_context,
+				   &fwd_data,
+				   delegated_cred_handle);
+   krb5_data_free(&fwd_data);
+
+   return ret;
+}
Index: heimdal/lib/gssapi/accept_sec_context.c
diff -u heimdal/lib/gssapi/accept_sec_context.c:1.1.1.1 heimdal/lib/gssapi/accept_sec_context.c:1.1.1.1.2.1
--- heimdal/lib/gssapi/accept_sec_context.c:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/accept_sec_context.c	Mon Aug 12 13:11:31 2002
@@ -62,6 +62,84 @@
 }
 
 OM_uint32
+gssapi_krb5_rd_delegation(OM_uint32 *minor_status,
+                          krb5_context context,
+                          krb5_auth_context ac,
+	    	          krb5_data *fwd_creds,
+		          gss_cred_id_t *delegated_cred_handle)
+{
+   krb5_error_code kret;
+   krb5_creds **creds = NULL;
+   gss_cred_id_t cred_handle = NULL;
+   OM_uint32 ret;
+   OM_uint32 minor_status2;
+
+   kret = krb5_rd_cred(context, ac, fwd_creds, &creds, NULL);
+   if (kret)
+      goto krb5_bad;
+
+   cred_handle = malloc(sizeof(*cred_handle));
+   if (cred_handle == NULL) {
+      kret = ENOMEM;
+      goto krb5_bad;
+   }
+   memset(cred_handle, 0, sizeof(*cred_handle));
+
+   ret = gss_duplicate_name(minor_status, (*creds)->client,
+	                     &cred_handle->principal);
+   if (kret)
+      goto gssapi_bad;
+
+   cred_handle->keytab = NULL;
+   cred_handle->lifetime = (*creds)->times.endtime;
+   cred_handle->usage = GSS_C_BOTH;
+
+   ret = gss_create_empty_oid_set(minor_status, &cred_handle->mechanisms);
+   if (ret)
+      goto gssapi_bad;
+
+   ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+	 			&cred_handle->mechanisms);
+   if (ret)
+      goto gssapi_bad;
+
+   kret = krb5_cc_gen_new(context, &krb5_mcc_ops, &cred_handle->ccache);
+   if (kret)
+      goto krb5_bad;
+
+   kret = krb5_cc_initialize(context, cred_handle->ccache, (*creds)->client);
+   if (kret)
+      goto krb5_bad;
+
+   kret = krb5_cc_store_cred(context, cred_handle->ccache, *creds);
+   if (kret)
+      goto krb5_bad;
+
+   if (*delegated_cred_handle != GSS_C_NO_CREDENTIAL)
+      gss_release_cred(&minor_status2, delegated_cred_handle);
+
+   *delegated_cred_handle = cred_handle;
+   cred_handle = NULL;
+
+   krb5_free_creds(context, *creds);
+
+   return GSS_S_COMPLETE;
+
+krb5_bad:
+   *minor_status = kret;
+   gssapi_krb5_set_error_string();
+   ret = GSS_S_FAILURE;
+
+gssapi_bad:
+   if (creds)
+      krb5_free_creds(context, *creds);
+   if (cred_handle)
+      gss_release_cred(&minor_status2, &cred_handle);
+
+   return ret;
+}
+
+OM_uint32
 gss_accept_sec_context
            (OM_uint32 * minor_status,
             gss_ctx_id_t * context_handle,
@@ -284,76 +362,18 @@
 	goto failure;
   }
 
-  if (fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) {
-      
-      krb5_ccache ccache;
-      
-      if (delegated_cred_handle == NULL)
-         /* XXX Create a new delegated_cred_handle? */
-         kret = krb5_cc_default (gssapi_krb5_context, &ccache);
-      else if (*delegated_cred_handle == NULL) {
-	 if ((*delegated_cred_handle =
-	      calloc(1, sizeof(**delegated_cred_handle))) == NULL) {
-	    ret = GSS_S_FAILURE;
-	    *minor_status = ENOMEM;
-	    krb5_set_error_string(gssapi_krb5_context, "out of memory");
-	    gssapi_krb5_set_error_string();
-	    goto failure;
-	 }
-	 if ((ret = gss_duplicate_name(minor_status, ticket->client,
-				&(*delegated_cred_handle)->principal)) != 0) {
-	    flags &= ~GSS_C_DELEG_FLAG;
-	    free(*delegated_cred_handle);
-	    *delegated_cred_handle = NULL;
-	    goto end_fwd;
-	 }
-      }
-      if (delegated_cred_handle != NULL &&
-	  (*delegated_cred_handle)->ccache == NULL) {
-            kret = krb5_cc_gen_new (gssapi_krb5_context,
-                                    &krb5_mcc_ops,
-                                    &(*delegated_cred_handle)->ccache);
-         ccache = (*delegated_cred_handle)->ccache;
-      }
-      if (delegated_cred_handle != NULL &&
-	  (*delegated_cred_handle)->mechanisms == NULL) {
-	    ret = gss_create_empty_oid_set(minor_status, 
-			&(*delegated_cred_handle)->mechanisms);
-            if (ret)
-              goto failure;
-	    ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
-			&(*delegated_cred_handle)->mechanisms);
-	    if (ret)
-	      goto failure;
-      }
-
-      if (kret) {
-         flags &= ~GSS_C_DELEG_FLAG;
-         goto end_fwd;
-      }
-      
-      kret = krb5_cc_initialize(gssapi_krb5_context,
-                                ccache,
-                                *src_name);
-      if (kret) {
-         flags &= ~GSS_C_DELEG_FLAG;
-         goto end_fwd;
-      }
-      
-      kret = krb5_rd_cred2(gssapi_krb5_context,
-			   (*context_handle)->auth_context,
-			   ccache,
-			   &fwd_data);
-      if (kret) {
-         flags &= ~GSS_C_DELEG_FLAG;
-         goto end_fwd;
-      }
+  if (delegated_cred_handle != NULL &&
+      fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) {
 
-end_fwd:
-      free(fwd_data.data);
+     ret = gssapi_krb5_rd_delegation(minor_status,
+	   	  		     gssapi_krb5_context, 
+	                             (*context_handle)->auth_context,
+				     &fwd_data,
+				     delegated_cred_handle);
+     if (ret)
+	goto failure;
   }
-         
-
+     
   flags |= GSS_C_TRANS_FLAG;
 
   if (ret_flags)
Index: heimdal/lib/gssapi/display_status.c
diff -u heimdal/lib/gssapi/display_status.c:1.1.1.1 heimdal/lib/gssapi/display_status.c:1.1.1.1.2.1
--- heimdal/lib/gssapi/display_status.c:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/display_status.c	Mon Aug 12 14:50:45 2002
@@ -122,7 +122,7 @@
   *minor_status = 0;
 
   if (mech_type != GSS_C_NO_OID &&
-      mech_type != GSS_KRB5_MECHANISM)
+      !g_OID_equal(mech_type, GSS_KRB5_MECHANISM))
       return GSS_S_BAD_MECH;
 
   if (status_type == GSS_C_GSS_CODE) {
Index: heimdal/lib/gssapi/export_cred.c
diff -u /dev/null heimdal/lib/gssapi/export_cred.c:1.1.2.4
--- /dev/null	Sun Aug 18 17:18:27 2002
+++ heimdal/lib/gssapi/export_cred.c	Fri Aug 16 11:52:59 2002
@@ -0,0 +1,157 @@
+#include "gssapi_locl.h"
+
+RCSID("$Id$");
+
+#if 0
+/* lze pouzit gss_release_buffer() na output token? Nejaka takova fce na
+ * vymazani 
+   exportovanych cred by mela existovat. Stacilo by rict, ze vysledek
+   gss_export_cred() musi byt uvolnitelny pres gss_release_buffer() */
+
+/* lze rict pouzij defaultni ccache ?? */
+
+/* lze delegovat vice creds naraz? */
+
+/* je k necemu parametr time_req v gss_import_cred ? */
+#endif
+
+/* Dump credentials to buffer. Simple gss_release_buffer can be used to free 
+   them. */
+static krb5_error_code
+cred_encode(krb5_context context,
+	    krb5_ccache  ccache,
+      	    gss_buffer_t buffer)
+{
+   krb5_storage *sp;
+   krb5_error_code ret;
+   krb5_cc_cursor cursor;
+   krb5_creds creds;
+   krb5_data encoded_creds;
+
+   memset(&creds, 0, sizeof(creds));
+   memset(&encoded_creds, 0, sizeof(encoded_creds));
+
+   sp = krb5_storage_emem();
+   if (sp == NULL)
+      return ENOMEM;
+
+   /* suppose only one ticket is delegated by the client so it's sufficient to
+      process only the first credential from ccache. */
+   krb5_cc_start_seq_get(context, ccache, &cursor);
+   ret = krb5_cc_next_cred(context, ccache, &cursor, &creds);
+   krb5_cc_end_seq_get(context, ccache, &cursor);
+   if (ret)
+      goto end;
+
+   ret = krb5_store_creds(sp, &creds);
+   if (ret)
+     goto end;
+
+   ret = krb5_storage_to_data(sp, &encoded_creds);
+   if (ret)
+     goto end;
+
+   buffer->length = encoded_creds.length;
+   buffer->value  = encoded_creds.data;
+   krb5_data_zero(&encoded_creds);
+
+   ret = 0;
+
+end:
+   krb5_free_creds_contents(context, &creds);
+   if (encoded_creds.length > 0)
+      krb5_data_free(&encoded_creds);
+   krb5_storage_free(sp);
+
+   return ret;
+}
+
+/* Copy ccache to disc and return its identificator (filename) */
+static krb5_error_code
+cred_store(krb5_context context,
+      	    krb5_ccache  src_ccache,
+	    gss_buffer_t buffer)
+{
+   krb5_error_code problem;
+   krb5_ccache ccache = NULL;
+   krb5_principal princ = NULL;
+
+   problem = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache);
+   if (problem)
+      return problem;
+
+   problem = krb5_cc_get_principal(context, src_ccache, &princ);
+   if (problem)
+      goto end;
+
+   problem = krb5_cc_initialize(context, ccache, princ);
+   if (problem)
+      goto end;
+
+   problem = krb5_cc_copy_cache(context, src_ccache, ccache);
+   if (problem)
+      goto end;
+
+   buffer->length = asprintf((char**) &buffer->value, "KRB5CCNAME=%s",
+	                     krb5_cc_get_name(context, ccache));
+   if (buffer->length == 0) {
+      problem = ENOMEM;
+      goto end;
+   }
+
+   problem = 0;
+
+end:
+   if (problem)
+      krb5_cc_destroy(context, ccache);
+   else
+      krb5_cc_close(context, ccache);
+
+   if (princ)
+      krb5_free_principal(context, princ);
+
+   return problem;
+}
+
+OM_uint32 gss_export_cred
+           (OM_uint32 * minor_status,
+            const gss_cred_id_t cred_handle,
+            const gss_OID desired_mech,
+            OM_uint32 option_req,
+            gss_buffer_t export_buffer
+           )
+{
+   krb5_error_code problem;
+
+   gssapi_krb5_init();
+   *minor_status = 0;
+
+   if (cred_handle == GSS_C_NO_CREDENTIAL)
+      return GSS_S_NO_CRED;
+
+   if (desired_mech != GSS_C_NO_OID &&
+       !g_OID_equal(desired_mech, GSS_KRB5_MECHANISM))
+      return GSS_S_BAD_MECH;
+
+   if (export_buffer == GSS_C_NO_BUFFER)
+      return GSS_S_FAILURE;
+
+   if (option_req == 0)
+      problem = cred_encode(gssapi_krb5_context, cred_handle->ccache,
+	                    export_buffer);
+   else if (option_req == 1) {
+      problem = cred_store(gssapi_krb5_context, cred_handle->ccache, 
+	    		   export_buffer);
+   } else {
+      *minor_status = KRB5KRB_ERR_GENERIC;
+      return GSS_S_FAILURE;
+   }
+
+   if (problem) {
+      gssapi_krb5_set_error_string();
+      *minor_status = problem;
+      return GSS_S_FAILURE;
+   }
+
+   return GSS_S_COMPLETE;
+}
Index: heimdal/lib/gssapi/gssapi.h
diff -u heimdal/lib/gssapi/gssapi.h:1.1.1.1 heimdal/lib/gssapi/gssapi.h:1.1.1.1.2.1
--- heimdal/lib/gssapi/gssapi.h:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/gssapi.h	Mon Aug 12 13:11:31 2002
@@ -770,4 +770,97 @@
 	 gss_cred_id_t cred,
 	 struct krb5_ccache_data *out);
 
+/*
+ * GSS-API extensions defined by GGF draft 
+ * (http://www.gridforum.org/2_SEC/GSI.htm)
+ */
+
+typedef struct gss_buffer_set_desc_struct {
+	size_t                 count;
+	gss_buffer_desc *      elements;
+} gss_buffer_set_desc, *gss_buffer_set_t;
+
+OM_uint32
+gss_create_empty_buffer_set(
+	OM_uint32 *            minor_status,
+	gss_buffer_set_t *     buffer_set);
+
+OM_uint32
+gss_add_buffer_set_member(
+	OM_uint32 *            minor_status,
+	const gss_buffer_t     member_buffer,
+	gss_buffer_set_t *     buffer_set);
+
+OM_uint32
+gss_release_buffer_set(
+	OM_uint32 *            minor_status,
+	gss_buffer_set_t       buffer_set);
+
+OM_uint32
+gss_export_cred(
+	OM_uint32 *            minor_status,
+	const gss_cred_id_t    cred_handle,
+	const gss_OID          desired_mech,
+	OM_uint32              option_req,
+	gss_buffer_t           export_buffer);
+
+OM_uint32
+gss_import_cred(
+	OM_uint32 *            minor_status,
+	gss_cred_id_t *        output_cred_handle,
+	const gss_OID          desired_mech,
+	OM_uint32              option_req,
+	const gss_buffer_t     import_buffer,
+	OM_uint32              time_req,
+	OM_uint32 *            time_rec);
+
+OM_uint32
+gss_init_delegation(
+	OM_uint32 *            minor_status,
+	const gss_ctx_id_t     context_handle,
+	const gss_cred_id_t    cred_handle,
+	const gss_OID          desired_mech,
+	const gss_OID_set      extension_oids,
+	const gss_buffer_set_t extension_buffers,
+	const gss_buffer_t     input_token,
+	OM_uint32              time_req,
+	gss_buffer_t           output_token);
+
+OM_uint32
+gss_accept_delegation(
+	OM_uint32 *            minor_status,
+	const gss_ctx_id_t     context_handle,
+	const gss_OID_set      extension_oids,
+	const gss_buffer_set_t extension_buffers,
+	const gss_buffer_t     input_token,
+	OM_uint32              time_req,
+	OM_uint32 *            time_rec,
+	gss_cred_id_t *        delegated_cred_handle,
+	gss_OID *              mech_type, 
+	gss_buffer_t           output_token);
+
+
+OM_uint32
+gss_inquire_sec_context_by_oid(
+    OM_uint32 *                minor_status,
+    const gss_ctx_id_t         context_handle,
+    gss_OID                    desired_object,
+    gss_buffer_set_t           data_set);
+
+
+OM_uint32
+gss_inquire_cred_by_oid(
+    OM_uint32 *                         minor_status,
+    const gss_cred_id_t                 cred_handle,
+    const gss_OID                       desired_object,
+    gss_buffer_set_t *                  data_set);
+
+OM_uint32
+gss_set_sec_context_option(
+    OM_uint32 *                minor_status,
+    gss_ctx_id_t *             context_handle,
+    gss_OID                    option,
+    gss_buffer_t               value);
+
+
 #endif /* GSSAPI_H_ */
Index: heimdal/lib/gssapi/gssapi_locl.h
diff -u heimdal/lib/gssapi/gssapi_locl.h:1.1.1.1 heimdal/lib/gssapi/gssapi_locl.h:1.1.1.1.2.2
--- heimdal/lib/gssapi/gssapi_locl.h:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/gssapi_locl.h	Mon Aug 12 14:50:45 2002
@@ -44,6 +44,11 @@
 #include <gssapi.h>
 #include <assert.h>
 
+#define g_OID_equal(o1,o2) \
+	(((o1) == (o2)) || \
+	 ((o1) && (o2) && ((o1)->length == (o2)->length) && \
+	  (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)))
+
 extern krb5_context gssapi_krb5_context;
 
 extern krb5_keytab gssapi_krb5_keytab;
@@ -123,4 +128,18 @@
 char *
 gssapi_krb5_get_error_string (void);
 
+void
+gssapi_krb5_do_delegation (krb5_auth_context ac,
+                           krb5_ccache ccache,
+                           krb5_creds *cred,
+                           const gss_name_t target_name,
+                           krb5_data *fwd_data,
+                           int *flags);
+
+OM_uint32
+gssapi_krb5_rd_delegation(OM_uint32 *minor_status,
+                          krb5_context context,
+                          krb5_auth_context ac,
+                          krb5_data *fwd_creds,
+                          gss_cred_id_t *delegated_cred_handle);
 #endif
Index: heimdal/lib/gssapi/import_cred.c
diff -u /dev/null heimdal/lib/gssapi/import_cred.c:1.1.2.6
--- /dev/null	Sun Aug 18 17:18:27 2002
+++ heimdal/lib/gssapi/import_cred.c	Fri Aug 16 12:46:25 2002
@@ -0,0 +1,165 @@
+#include "gssapi_locl.h"
+
+RCSID("$Id$");
+
+#if 0
+- neni desired_mech zbytecny? gss_import_sec_context nic takoveho nema.
+#endif
+
+OM_uint32 gss_import_cred
+           (OM_uint32      * minor_status,
+	    gss_cred_id_t  * output_cred_handle,
+	    const gss_OID    desired_mech,
+	    OM_uint32        option_req,
+	    const gss_buffer_t  import_buffer,
+	    OM_uint32        time_req,
+	    OM_uint32      * time_rec)
+{
+   krb5_error_code problem;
+   OM_uint32 ret;
+   gss_cred_id_t handle = NULL;
+   krb5_ccache ccache = NULL;
+   krb5_creds creds;
+   krb5_timestamp now;
+   krb5_storage *sp = NULL;
+
+   gssapi_krb5_init();
+   *minor_status = 0;
+
+   memset(&creds, 0, sizeof(creds));
+
+   if (output_cred_handle == NULL)
+      return GSS_S_NO_CRED;
+
+   if (desired_mech != GSS_C_NO_OID &&
+       !g_OID_equal(desired_mech, GSS_KRB5_MECHANISM))
+      return GSS_S_BAD_MECH;
+
+   if (option_req != 0 && option_req != 1) {
+      return GSS_S_FAILURE;
+   }
+
+   if (import_buffer == GSS_C_NO_BUFFER || import_buffer->length <= 0)
+      return GSS_S_DEFECTIVE_TOKEN;
+
+   if (option_req == 0) {
+      sp = krb5_storage_from_mem (import_buffer->value,
+	                          import_buffer->length);
+      if (sp == NULL) {
+	 problem = ENOMEM;
+	 goto krb5_bad;
+      }
+
+      problem = krb5_ret_creds(sp, &creds);
+      if (problem)
+	goto krb5_bad;
+
+      problem = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops, &ccache);
+      if (problem)
+	 goto krb5_bad;
+
+      problem = krb5_cc_initialize(gssapi_krb5_context, ccache, creds.client);
+      if (problem)
+	 goto krb5_bad;
+
+      problem = krb5_cc_store_cred(gssapi_krb5_context, ccache, &creds);
+      if (problem)
+	 goto krb5_bad;
+   } else {
+      char *filename = NULL;
+      krb5_cc_cursor cursor;
+
+      filename = strchr((char *) import_buffer->value, '=');
+      if (filename == NULL) {
+	 ret = GSS_S_DEFECTIVE_TOKEN;
+	 goto gssapi_bad;
+      }
+      filename++;
+      problem = krb5_cc_resolve(gssapi_krb5_context, filename, &ccache);
+      if (problem)
+	 goto krb5_bad;
+
+      krb5_cc_start_seq_get(gssapi_krb5_context, ccache, &cursor);
+      problem = krb5_cc_next_cred(gssapi_krb5_context, ccache, &cursor, &creds);
+      krb5_cc_end_seq_get(gssapi_krb5_context, ccache, &cursor);
+      if (problem)
+	 goto krb5_bad;
+   }
+
+   handle = (gss_cred_id_t)malloc(sizeof(*handle));
+   if (handle == NULL) {
+      *minor_status = ENOMEM;
+      ret = GSS_S_FAILURE;
+      goto gssapi_bad;
+   }
+   memset(handle, 0, sizeof (*handle));
+
+   problem = krb5_cc_get_principal(gssapi_krb5_context, ccache, 
+	                           &handle->principal);
+   if (problem)
+      goto krb5_bad;
+
+   handle->usage = GSS_C_BOTH;
+
+   ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
+   if (ret)
+      goto gssapi_bad;
+
+   ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
+	                        &handle->mechanisms);
+   if (ret)
+      goto gssapi_bad;
+
+   if (handle->ccache)
+      krb5_cc_destroy(gssapi_krb5_context, handle->ccache);
+   handle->ccache = ccache;
+
+   problem = krb5_timeofday(gssapi_krb5_context, &now);
+   if (problem)
+      goto krb5_bad;
+
+   if (creds.times.endtime <= now) {
+      ret = GSS_S_CREDENTIALS_EXPIRED;
+      goto gssapi_bad;
+   }
+
+   if (time_req > 0)
+      /* XXX lifetime of the ticket is not changed -- another ticket would have
+	 to be fetched from KDC */ 
+      handle->lifetime = (time_req + now < creds.times.endtime) ? 
+	                 time_req + now : 
+			 creds.times.endtime;
+   else
+      handle->lifetime = creds.times.endtime;
+	    
+   if (time_rec != NULL)
+      *time_rec = handle->lifetime - now;
+
+   krb5_free_creds_contents(gssapi_krb5_context, &creds);
+   if (sp)
+      krb5_storage_free(sp);
+   
+   *output_cred_handle = handle;
+   return GSS_S_COMPLETE;
+
+krb5_bad:
+   ret = GSS_S_FAILURE;
+   *minor_status = problem;
+   gssapi_krb5_set_error_string ();
+
+gssapi_bad:
+   if (sp)
+      krb5_storage_free(sp);
+   krb5_free_creds_contents(gssapi_krb5_context, &creds);
+   if (ccache)
+      krb5_cc_close(gssapi_krb5_context, ccache);
+   if (handle) {
+      if (handle->principal)
+	 krb5_free_principal(gssapi_krb5_context, handle->principal);
+      if (handle->mechanisms)
+	 gss_release_oid_set(NULL, &handle->mechanisms);
+      free(handle);
+   }
+
+   return ret;
+}
Index: heimdal/lib/gssapi/import_name.c
diff -u heimdal/lib/gssapi/import_name.c:1.1.1.1 heimdal/lib/gssapi/import_name.c:1.1.1.1.2.1
--- heimdal/lib/gssapi/import_name.c:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/import_name.c	Mon Aug 12 14:50:45 2002
@@ -133,13 +133,13 @@
 {
     gssapi_krb5_init ();
 
-    if (input_name_type == GSS_C_NT_HOSTBASED_SERVICE)
+    if (g_OID_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE))
 	return import_hostbased_name (minor_status,
 				      input_name_buffer,
 				      output_name);
     else if (input_name_type == GSS_C_NO_OID
-	     || input_name_type == GSS_C_NT_USER_NAME
-	     || input_name_type == GSS_KRB5_NT_PRINCIPAL_NAME)
+	     || g_OID_equal(input_name_type, GSS_C_NT_USER_NAME)
+	     || g_OID_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME))
  	/* default printable syntax */
 	return import_krb5_name (minor_status,
 				 input_name_buffer,
Index: heimdal/lib/gssapi/init_delegation.c
diff -u /dev/null heimdal/lib/gssapi/init_delegation.c:1.1.2.3
--- /dev/null	Sun Aug 18 17:18:27 2002
+++ heimdal/lib/gssapi/init_delegation.c	Mon Aug 12 14:50:45 2002
@@ -0,0 +1,64 @@
+#include "gssapi_locl.h"
+
+RCSID("$Id$");
+
+OM_uint32 gss_init_delegation(
+	OM_uint32 *		minor_status,
+	const gss_ctx_id_t 	context_handle,
+	const gss_cred_id_t	cred_handle,
+	const gss_OID		desired_mech,
+	const gss_OID_set	extension_oids,
+	const gss_buffer_set_t	extension_buffers,
+	const gss_buffer_t	input_token,
+	OM_uint32		time_req,
+	gss_buffer_t		output_token)
+{
+   krb5_error_code kret = 0;
+   OM_uint32 ret;
+   krb5_ccache ccache = NULL;
+   krb5_creds creds;
+   u_int32_t flags = 0;
+   krb5_data fwd_data;
+
+   memset(&creds, 0, sizeof(&creds));
+   krb5_data_zero(&fwd_data);
+
+   gssapi_krb5_init();
+   *minor_status = 0;
+
+   if (context_handle == GSS_C_NO_CONTEXT)
+      return GSS_S_FAILURE;
+
+   if (desired_mech != GSS_C_NO_OID &&
+       !g_OID_equal(desired_mech, GSS_KRB5_MECHANISM))
+      return GSS_S_BAD_MECH;
+
+   if (cred_handle == GSS_C_NO_CREDENTIAL) {
+      kret = krb5_cc_default(gssapi_krb5_context, &ccache);
+      if (kret) {
+	 ret = GSS_S_FAILURE;
+	 *minor_status = kret;
+	 gssapi_krb5_set_error_string ();
+	 goto end;
+      }
+   } else
+      ccache = cred_handle->ccache;
+
+   flags = 0;
+   gssapi_krb5_do_delegation(context_handle->auth_context, ccache, &creds,
+	  	             context_handle->target, &fwd_data, &flags);
+   if (!(flags & GSS_C_DELEG_FLAG)) {
+      ret = GSS_S_FAILURE;
+      goto end;
+   }
+
+   ret = gssapi_krb5_encapsulate(minor_status, &fwd_data, output_token,
+	                         "\x05\x01");
+   if (ret) 
+      goto end; 
+
+   ret = GSS_S_COMPLETE;
+
+end:
+   return ret;
+}
Index: heimdal/lib/gssapi/init_sec_context.c
diff -u heimdal/lib/gssapi/init_sec_context.c:1.1.1.1 heimdal/lib/gssapi/init_sec_context.c:1.1.1.1.2.2
--- heimdal/lib/gssapi/init_sec_context.c:1.1.1.1	Tue Feb 26 15:42:04 2002
+++ heimdal/lib/gssapi/init_sec_context.c	Mon Aug 12 14:00:51 2002
@@ -101,13 +101,13 @@
  * handle delegated creds in init-sec-context
  */
 
-static void
-do_delegation (krb5_auth_context ac,
-	       krb5_ccache ccache,
-	       krb5_creds *cred,
-	       const gss_name_t target_name,
-	       krb5_data *fwd_data,
-	       int *flags)
+void
+gssapi_krb5_do_delegation (krb5_auth_context ac,
+	                   krb5_ccache ccache,
+	                   krb5_creds *cred,
+	                   const gss_name_t target_name,
+	                   krb5_data *fwd_data,
+	                   int *flags)
 {
     krb5_creds creds;
     krb5_kdc_flags fwd_flags;
@@ -117,14 +117,16 @@
     memset (&creds, 0, sizeof(creds));
     krb5_data_zero (fwd_data);
        
-    kret = krb5_generate_subkey (gssapi_krb5_context, &cred->session, &subkey);
-    if (kret)
-	goto out;
-       
-    kret = krb5_auth_con_setlocalsubkey(gssapi_krb5_context, ac, subkey);
-    krb5_free_keyblock (gssapi_krb5_context, subkey);
-    if (kret)
-	goto out;
+    if (ac->local_subkey == NULL) {
+       kret = krb5_generate_subkey (gssapi_krb5_context, &cred->session, &subkey);
+       if (kret)
+	   goto out;
+	  
+       kret = krb5_auth_con_setlocalsubkey(gssapi_krb5_context, ac, subkey);
+       krb5_free_keyblock (gssapi_krb5_context, subkey);
+       if (kret)
+	   goto out;
+    }
        
     kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client);
     if (kret) 
@@ -320,8 +322,8 @@
     flags = 0;
     ap_options = 0;
     if (req_flags & GSS_C_DELEG_FLAG)
-	do_delegation ((*context_handle)->auth_context,
-		       ccache, cred, target_name, &fwd_data, &flags);
+	gssapi_krb5_do_delegation((*context_handle)->auth_context,
+		                  ccache, cred, target_name, &fwd_data, &flags);
        
     if (req_flags & GSS_C_MUTUAL_FLAG) {
 	flags |= GSS_C_MUTUAL_FLAG;
Index: heimdal/lib/gssapi/padding.c
diff -u /dev/null heimdal/lib/gssapi/padding.c:1.1.2.3
--- /dev/null	Sun Aug 18 17:18:27 2002
+++ heimdal/lib/gssapi/padding.c	Mon Aug 12 14:28:28 2002
@@ -0,0 +1,116 @@
+#include "gssapi_locl.h"
+
+RCSID("$Id$");
+
+/* This file contains fake implementations of those functions which are 
+   described by the GSS-API rfc or GSS Extension draft and which are not 
+   implemented in Heimdal. */
+
+OM_uint32
+gss_process_context_token
+           (OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            const gss_buffer_t token_buffer
+           )
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_add_cred (
+            OM_uint32 * minor_status,
+            const gss_cred_id_t input_cred_handle,
+            const gss_name_t desired_name,
+            const gss_OID desired_mech,
+            gss_cred_usage_t cred_usage,
+            OM_uint32 initiator_time_req,
+            OM_uint32 acceptor_time_req,
+            gss_cred_id_t * output_cred_handle,
+            gss_OID_set * actual_mechs,
+            OM_uint32 * initiator_time_rec,
+            OM_uint32 * acceptor_time_rec
+           )
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_inquire_cred_by_mech (
+            OM_uint32 * minor_status,
+            const gss_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
+           )
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32 gss_inquire_names_for_mech (
+            OM_uint32 * minor_status,
+            const gss_OID mechanism,
+            gss_OID_set * name_types
+           )
+{
+   return GSS_S_FAILURE;
+}
+
+/* 
+   Functions from GSS-API Extension draft
+*/
+
+OM_uint32
+gss_create_empty_buffer_set(
+	OM_uint32 *            minor_status,
+	gss_buffer_set_t *     buffer_set)
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32
+gss_add_buffer_set_member(
+	OM_uint32 *            minor_status,
+	const gss_buffer_t     member_buffer,
+	gss_buffer_set_t *     buffer_set)
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32
+gss_release_buffer_set(
+	OM_uint32 *            minor_status,
+	gss_buffer_set_t       buffer_set)
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32
+gss_inquire_sec_context_by_oid(
+    OM_uint32 *                minor_status,
+    const gss_ctx_id_t         context_handle,
+    gss_OID                    desired_object,
+    gss_buffer_set_t           data_set)
+{
+   return GSS_S_FAILURE;
+}
+
+
+OM_uint32
+gss_inquire_cred_by_oid(
+    OM_uint32 *                         minor_status,
+    const gss_cred_id_t                 cred_handle,
+    const gss_OID                       desired_object,
+    gss_buffer_set_t *                  data_set)
+{
+   return GSS_S_FAILURE;
+}
+
+OM_uint32
+gss_set_sec_context_option(
+    OM_uint32 *                minor_status,
+    gss_ctx_id_t *             context_handle,
+    gss_OID                    option,
+    gss_buffer_t               value)
+{
+   return GSS_S_FAILURE;
+}