--- clean/include/linux/sunrpc/auth.h	Tue Feb 26 12:00:33 2002
+++ dirty/include/linux/sunrpc/auth.h	Mon Feb 25 12:08:45 2002
@@ -51,8 +51,6 @@
 	unsigned int		au_cslack;	/* call cred size estimate */
 	unsigned int		au_rslack;	/* reply verf size guess */
 	unsigned int		au_flags;	/* various flags */
-	uid_t           proxy_uid;
-	uid_t           proxy_gid;
 	struct rpc_authops *	au_ops;		/* operations */
 
 	/* per-flavor data */
@@ -75,7 +73,7 @@
 	struct rpc_cred *	(*crcreate)(struct rpc_task *);
 	void			(*crdestroy)(struct rpc_cred *);
 
-	int			(*crmatch)(struct rpc_cred *, int, int, int);
+	int			(*crmatch)(struct rpc_cred *, int);
 	u32 *			(*crmarshal)(struct rpc_task *, u32 *, int);
 	int			(*crrefresh)(struct rpc_task *);
 	u32 *			(*crvalidate)(struct rpc_task *, u32 *);
@@ -92,7 +90,7 @@
 int			rpcauth_unregister(struct rpc_authops *);
 struct rpc_auth *	rpcauth_create(unsigned int, struct rpc_clnt *);
 void			rpcauth_destroy(struct rpc_auth *);
-struct rpc_cred *	rpcauth_lookupcred(struct rpc_task *);
+struct rpc_cred *	rpcauth_lookupcred(struct rpc_auth *auth, int taskflags,struct rpc_task *);
 struct rpc_cred *	rpcauth_bindcred(struct rpc_task *);
 void			rpcauth_holdcred(struct rpc_task *);
 void			rpcauth_releasecred(struct rpc_auth *,
--- clean/include/linux/sunrpc/sched.h	Tue Feb 26 12:00:35 2002
+++ dirty/include/linux/sunrpc/sched.h	Mon Feb 25 12:08:45 2002
@@ -104,8 +104,8 @@
 #define RPC_TASK_KILLED		0x0100		/* task was killed */
 #define RPC_TASK_ROOT_CREDS	0x0200		/* XXX: really force root creds */
 #define RPC_TASK_DONTZERO	0x0400		/* don't memset buffer to zero */
-/*ANDROS*/
-#define RPC_TASK_PROXYCREDS 0x0800 /* use proxy_uid/gid */
+/*RPCSEC_GSS*/
+#define RPC_TASK_MACHINE_CREDS 0x0800  /* use machine gss credentials */
 
 #define RPC_IS_ASYNC(t)		((t)->tk_flags & RPC_TASK_ASYNC)
 #define RPC_IS_SETUID(t)	((t)->tk_flags & RPC_TASK_SETUID)
--- clean/include/linux/sunrpc/xdr.h	Tue Feb 26 12:00:35 2002
+++ dirty/include/linux/sunrpc/xdr.h	Mon Feb 25 12:08:45 2002
@@ -9,7 +9,11 @@
 
 #ifdef __KERNEL__
 
+#ifdef __linux__
 #include <linux/uio.h>
+#else
+#include <nfs4/nfs4.h>
+#endif
 
 /*
  * Buffer adjustment
--- clean/include/linux/sunrpc/gss_err.h	Tue Feb 26 12:04:09 2002
+++ dirty/include/linux/sunrpc/gss_err.h	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,174 @@
+/*
+ *  linux/include/sunrpc/gss_err.h
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 include/gssapi/gssapi.h
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifdef __linux__
+typedef unsigned int OM_uint32;
+#endif /* __linux__*/
+
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_SEQUENCE_FLAG 8
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+#define	GSS_C_ANON_FLAG 64
+#define GSS_C_PROT_READY_FLAG 128
+#define GSS_C_TRANS_FLAG 256
+
+/*
+ * Credential usage options
+ */
+#define GSS_C_BOTH 0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT 2
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+
+/*
+ * Define the default Quality of Protection for per-message services.  Note
+ * that an implementation that offers multiple levels of QOP may either reserve
+ * a value (for example zero, as assumed here) to mean "default protection", or
+ * alternatively may simply equate GSS_C_QOP_DEFAULT to a specific explicit
+ * QOP value.  However a value of 0 should always be interpreted by a GSSAPI
+ * implementation as a request for the default protection level.
+ */
+#define GSS_C_QOP_DEFAULT 0
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful)
+
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul)
+#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul)
+
+/*
+ * The macros that test status codes for error conditions.  Note that the
+ * GSS_ERROR() macro has changed slightly from the V1 GSSAPI so that it now
+ * evaluates its argument only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+  ((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+  ((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+  ((x) & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+  ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+	  (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Now the actual status code definitions
+ */
+
+/*
+ * Calling errors:
+ */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+                             (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+                             (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+                             (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET)
+
+/*
+ * Routine errors:
+ */
+#define GSS_S_BAD_MECH (((OM_uint32) 1ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME (((OM_uint32) 2ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE (((OM_uint32) 3ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_BINDINGS (((OM_uint32) 4ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS (((OM_uint32) 5ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG (((OM_uint32) 6ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CRED (((OM_uint32) 7ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT (((OM_uint32) 8ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN (((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL \
+     (((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED \
+     (((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED \
+     (((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT \
+     (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN \
+     (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET)
+
+/*
+ * Supplementary info bits:
+ */
+#define GSS_S_CONTINUE_NEEDED (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+/* XXXX these are not part of the GSSAPI C bindings!  (but should be) */
+
+#define GSS_CALLING_ERROR_FIELD(x) \
+   (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
+#define GSS_ROUTINE_ERROR_FIELD(x) \
+   (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
+#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
+   (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
+
+/* XXXX This is a necessary evil until the spec is fixed */
+#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE
+
--- clean/include/linux/sunrpc/auth_gss.h	Tue Feb 26 12:04:09 2002
+++ dirty/include/linux/sunrpc/auth_gss.h	Mon Feb 25 12:54:57 2002
@@ -0,0 +1,242 @@
+/*
+ * linux/include/linux/auth_gss.h
+ *
+ * Declarations for RPCSEC_GSS
+ *
+ * Dug Song <dugsong@monkey.org>
+ * Andy Adamson <andros@umich.edu>
+ * Copyright (c) 2000 The Regents of the University of Michigan
+ *
+ * $Id: rpcsec_gss_nfsv4patch3.0.patch,v 1.2 2002/02/26 17:39:36 andros Exp $
+ */
+
+#ifndef _LINUX_SUNRPC_AUTH_GSS_H
+#define _LINUX_SUNRPC_AUTH_GSS_H
+
+#ifdef __KERNEL__
+#ifdef __linux__
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/svc.h>
+#endif
+
+/*
+ * GSS-API definitions.
+ */
+
+typedef struct xdr_netobj	GSS_CTX_ID_T;
+typedef struct xdr_netobj	GSS_CRED_ID_T;
+typedef struct xdr_netobj	GSS_OID;
+typedef struct xdr_netobj	GSS_BUFFER_T;
+
+#define GSS_C_NO_BUFFER		((GSS_BUFFER_T) 0)
+#define GSS_C_NO_CONTEXT	((GSS_CTX_ID_T) 0)
+#define GSS_C_NULL_OID		((GSS_OID) 0)
+
+#if 0
+#define GSS_C_QOP_DEFAULT	0
+
+#define GSS_S_COMPLETE		       0
+#define GSS_S_CONTINUE_NEEDED	   1
+#define GSS_S_DUPLICATE_TOKEN    2
+#define GSS_S_OLD_TOKEN          4
+#define GSS_S_UNSEQ_TOKEN        8
+#define GSS_S_GAP_TOKEN          16
+
+/* NOTE: the following were taken from MIT kerberos code, 
+ * ../lib/gssapi/generic/gssapi.h
+ */
+#define GSS_S_BAD_SIG           393216
+#define GSS_S_NO_CRED           458752
+#define GSS_S_NO_CONTEXT        524288
+#define GSS_S_DEFECTIVE_TOKEN   589824        
+#define GSS_S_FAILURE           851968
+#define GSS_S_CONTEXT_EXPIRED   786432
+
+#endif /*0*/
+
+extern GSS_OID gss_mech_krb5_oid;
+
+/*
+ * RPCSEC_GSS definitions.
+ */
+
+#define RPC_GSS_VERSION		1
+
+enum rpc_gss_proc {
+	RPC_GSS_PROC_DATA = 0,
+	RPC_GSS_PROC_INIT = 1,
+	RPC_GSS_PROC_CONTINUE_INIT = 2,
+	RPC_GSS_PROC_DESTROY = 3
+};
+
+enum rpc_gss_svc {
+	RPC_GSS_SVC_NONE = 1,
+	RPC_GSS_SVC_INTEGRITY = 2,
+	RPC_GSS_SVC_PRIVACY = 3
+};
+
+/* on the wire gss cred */
+struct rpc_gss_cred {
+	u32		gc_v;		/* version */
+	u32		gc_proc;	/* control procedure */
+	u32		gc_seq;		/* sequence number */
+	u32		gc_svc;		/* service */
+	GSS_BUFFER_T	gc_ctx;		/* context handle */
+};
+
+/* return from gss NULL PROC init sec context */
+struct rpc_gss_init_res {
+	GSS_BUFFER_T	gr_ctx;		/* context handle */
+	u32		gr_major;	/* major status */
+	u32		gr_minor;	/* minor status */
+	u32		gr_win;		/* sequence window */
+	GSS_BUFFER_T	gr_token;	/* token */
+};
+
+/* supported security triples */
+struct sup_sec_triple {
+	GSS_OID *oid;
+	u32     qop;
+	u32     service;
+};
+
+/*
+ * GSS Context Cache
+ */
+
+
+#define GSS_CTX_MAX     2048 /* arbitrary limit on context size */
+
+/* client gss context cache */
+struct gss_ctx_mapping {
+        rwlock_t                lock;
+        struct list_head        gss_ctx_cache;
+};
+
+
+/* chuck suggested that this should be a dynamically allocated 
+ * hash table size, dependant on the amount of memory on the machine. 
+ */
+#define GSS_HASH_BITS   8
+#define GSS_HASH_SIZE   (1 << GSS_HASH_BITS)
+#define GSS_HASH_MASK   (GSS_HASH_SIZE - 1)
+
+/* server gss context cache */
+struct gss_svc_ctx_mapping {
+        rwlock_t                lock;
+        struct list_head        gss_ctx_cache[GSS_HASH_SIZE];
+};
+
+struct gss_ctx_cacheent {
+        GSS_OID			gcc_mech;
+        u32			gcc_qop;
+        void		*gcc_ctx; /* pointer to mechanism specific context */
+
+/* fields after this point are private, for use by the gss cache */ 
+        atomic_t		gcc_refcount;
+        struct list_head	gss_ctx_cache;
+};
+
+#ifndef __OpenBSD__
+/* Client cred structure. 
+ *     gc_ctx_id is really a type gss_union_ctx_id_t 
+ *     (see mit kerberos v5 ../lib/gssapi/mechglue code)
+ *     that contains the mechanism OID as well as a pointer to
+ *     the current client context which before gssd_import_sec_context() 
+ *     points to gssd's per mech userland context store 
+ *     and after gssd_import_sec_context () points to the kernel
+ *     context stored in a gss_ctx_cacheent in the gss_ctx_map cache.
+ *
+ *     The clients reference to the SERVER's corresponding 
+ *     context is stored in gc_cred.gc_ctx, and is what is 
+ *     placed on the wire.
+ */
+struct gss_cred {
+        struct rpc_cred         gc_base;
+        u32                     gc_established;
+        GSS_BUFFER_T            gc_wire_verf;
+        GSS_BUFFER_T		        gc_service_name;
+        GSS_CTX_ID_T		        gc_ctx_id;
+        struct gss_ctx_mapping  gc_ctx_map;
+        u32                     gc_win;
+        struct rpc_gss_cred     gc_cred;
+};
+#define gc_uid                  gc_base.cr_uid
+#define gc_count                gc_base.cr_count
+#define gc_flags                gc_base.cr_flags
+#define gc_expire               gc_base.cr_expire
+#endif
+
+/* gss cache function declarations*/
+
+struct gss_ctx_cacheent * gss_ctx_alloc(void);
+void gss_ctx_free(struct gss_ctx_cacheent *p);
+struct gss_ctx_cacheent * gss_create_cacheent(struct gss_ctx_mapping *map);
+u32 gss_get_context(u32 *maj_stat, u32* min_stat,struct gss_ctx_mapping *map, GSS_CTX_ID_T *ctx);
+u32 gss_svc_get_context(u32 *maj_stat, u32* min_stat, GSS_CTX_ID_T *ctx);
+u32 gss_get_ctx_mech(GSS_OID *mech,GSS_CTX_ID_T *ctx_id);
+u32 gss_set_ctx(GSS_CTX_ID_T *ctx_id,struct gss_ctx_cacheent *cep);
+u32 gss_validate_context(GSS_CTX_ID_T *ctx_id,struct gss_ctx_mapping *map);
+u32 gss_svc_validate_context(GSS_CTX_ID_T *ctx_id);
+
+
+static inline void
+gss_ctx_put(struct gss_ctx_cacheent *p)
+{
+        if (atomic_dec_and_test(&p->gcc_refcount))
+                gss_ctx_free(p);
+}
+
+
+/* Crypto interface */
+int gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service);
+
+void print_digest(unsigned char *md,int len);                                                
+int gss_get_mic(u32                  *minor_status, 
+                GSS_CTX_ID_T         *contextid, 
+                u32                  qop, 
+		GSS_BUFFER_T         *message_buffer, 
+		GSS_BUFFER_T         *message_token);                                      
+int
+gss_verify_mic(u32                    *minor_status, 
+               GSS_CTX_ID_T           *contextid, 
+               GSS_BUFFER_T           *signbuf,
+               GSS_BUFFER_T           *checksum, 
+               u32                    *qstate);                                             
+/*
+ * GSSD gss_sec interface.
+ */
+
+int gssd_client_test(struct xdr_netobj *name, u32 *uidp);
+
+int gssd_init_sec_context(u32			uid,
+			  u32		       flags,
+			  u32		       *maj_statp,
+			  u32		       *min_statp,
+			  GSS_CTX_ID_T	       *ctx_id,
+			  GSS_BUFFER_T	       *service_name,
+			  GSS_OID	       *mech,
+			  GSS_BUFFER_T	       *input_tokenp,
+			  GSS_BUFFER_T	       *output_token,
+			  u32		       *ret_flagsp);
+     
+int gssd_accept_sec_context(u32		       *maj_statp,
+			    u32		       *min_statp,
+			    GSS_CTX_ID_T       *ctx_id,
+			    GSS_BUFFER_T       *input_token,
+			    GSS_BUFFER_T       *client_namep,
+			    GSS_BUFFER_T       *output_tokenp,
+			    u32		       *ret_flagsp);
+
+int
+gssd_import_sec_context(u32             *maj_statp,
+                        u32             *min_statp,
+                        GSS_CTX_ID_T    *ctx_id,
+                        GSS_BUFFER_T    *context_token); 
+int
+xdr_encode_rpc_gss_init_res(struct svc_rqst *req, u32 *p,
+			    struct rpc_gss_init_res *resp);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_SUNRPC_AUTH_GSS_H */
+
--- clean/include/linux/sunrpc/gss_krb5_types.h	Tue Feb 26 12:04:09 2002
+++ dirty/include/linux/sunrpc/gss_krb5_types.h	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,597 @@
+/*
+ *  linux/include/linux/sunrpc/gss_krb5_types.h
+ *
+ *  krb5 types mapped to linux kernel types
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h,
+ *  lib/gssapi/krb5/gssapiP_krb5.h, and others
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1995 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 <linux/sunrpc/auth_gss.h>
+#include <linux/sunrpc/gss_err.h>
+
+#define SIZEOF_INT 4
+
+#if (SIZEOF_INT == 4)
+typedef int krb5_int32;
+typedef unsigned int  krb5_ui_4;
+#define VALID_INT_BITS    0x7fffffff
+#define VALID_UINT_BITS   0xffffffff
+#elif (SIZEOF_LONG == 4)
+typedef long  krb5_int32;
+typedef unsigned long krb5_ui_4;
+#elif (SIZEOF_SHORT == 4)
+typedef short krb5_int32;
+typedef unsigned short  krb5_ui_4;
+#else
+ ?== error: undefined 32 bit type
+#endif
+
+/* temporary type*/
+typedef krb5_int32 krb5_context;
+
+typedef unsigned int krb5_boolean;
+typedef void * krb5_pointer;
+typedef krb5_int32  krb5_error_code;
+typedef krb5_error_code krb5_magic;
+typedef krb5_int32 krb5_enctype;
+typedef unsigned char krb5_octet;
+typedef krb5_int32  krb5_timestamp;
+typedef krb5_int32  krb5_flags;
+typedef krb5_int32 krb5_addrtype;
+typedef krb5_int32 krb5_authdatatype;
+typedef krb5_int32 krb5_cksumtype;
+typedef krb5_int32 krb5_keyusage;
+
+
+typedef struct _krb5_data {
+  krb5_magic magic;
+  int length;
+  char *data;
+} krb5_data;
+
+/* krb5 principal (krb5.h) */
+typedef struct krb5_principal_data {
+    krb5_magic magic;
+    krb5_data realm;
+    krb5_data *data;    /* An array of strings */
+    krb5_int32 length;
+    krb5_int32 type;
+} krb5_principal_data;
+
+typedef krb5_principal_data * krb5_principal;
+
+/* krb5 keyblock */
+
+typedef struct _krb5_keyblock {
+    krb5_magic magic;
+    krb5_enctype enctype;
+    int length;
+    krb5_octet *contents;
+} krb5_keyblock;
+
+struct krb5_keyhash_provider {
+    void (*hash_size)
+    (size_t *output);
+
+    krb5_error_code (*hash) 
+    (krb5_keyblock *key, krb5_data *ivec,
+      krb5_data *input, krb5_data *output);
+
+    krb5_error_code (*verify)
+    (krb5_keyblock *key, krb5_data *ivec,
+      krb5_data *input, krb5_data *hash,
+      krb5_boolean *valid);
+};
+
+struct krb5_hash_provider {
+    void (*hash_size)
+    (size_t *output);
+
+    void (*block_size)
+    (size_t *output);
+
+    /* this takes multiple inputs to avoid lots of copying. */
+    krb5_error_code (*hash) 
+    (unsigned int icount, krb5_data *input, krb5_data *output);
+};
+
+typedef struct _krb5_2_linux_digest {
+    krb5_cksumtype ctype;
+    char *digest_name;
+    struct krb5_hash_provider *hash;
+    struct krb5_keyhash_provider *keyhash;
+}krb5_2_linux_digest;
+
+typedef struct _krb5_2_linux_keytypes {
+    krb5_enctype enctype;
+    char *seal_name;
+    char *sign_name;
+}krb5_2_linux_keytypes;
+
+/* structure for address */
+typedef struct _krb5_address {
+    krb5_magic magic;
+    krb5_addrtype addrtype;
+    int length;
+    krb5_octet *contents;
+} krb5_address;
+
+/* structure for auth data */
+typedef struct _krb5_authdata {
+    krb5_magic magic;
+    krb5_authdatatype ad_type;
+    int length;
+    krb5_octet *contents;
+} krb5_authdata;
+
+typedef struct _krb5_checksum {
+    krb5_magic magic;
+    krb5_cksumtype checksum_type; /* checksum type */
+    int length;
+    krb5_octet *contents;
+} krb5_checksum;
+
+
+/* the unencrypted version */
+typedef struct _krb5_authenticator {
+    krb5_magic magic;
+    krb5_principal client;    /* client name/realm */
+    krb5_checksum *checksum;  /* checksum, includes type, optional */
+    krb5_int32 cusec;     /* client usec portion */
+    krb5_timestamp ctime;   /* client sec portion */
+    krb5_keyblock *subkey;    /* true session key, optional */
+    krb5_int32 seq_number;    /* sequence #, optional */
+    krb5_authdata * *authorization_data; /* New add by Ari, auth data */} krb5_authenticator;
+
+
+typedef struct krb5_rc_st {
+    krb5_magic magic;
+    struct _krb5_rc_ops *ops;
+    krb5_pointer data;
+} *krb5_rcache;
+
+typedef struct _krb5_rc_ops {
+    krb5_magic magic;
+    char *type;
+#if 0  /* ANDROS: don't know if i'll need theses...*/
+    krb5_error_code ( *init)
+  ((krb5_context, krb5_rcache,krb5_deltat)); /* create */
+    krb5_error_code ( *recover)
+  ((krb5_context, krb5_rcache)); /* open */
+    krb5_error_code ( *destroy)
+  ((krb5_context, krb5_rcache));
+    krb5_error_code ( *close)
+  ((krb5_context, krb5_rcache));
+    krb5_error_code ( *store)
+  ((krb5_context, krb5_rcache,krb5_donot_replay *));
+    krb5_error_code ( *expunge)
+  ((krb5_context, krb5_rcache));
+    krb5_error_code ( *get_span)
+  ((krb5_context, krb5_rcache,krb5_deltat *));
+    char *( *get_name)
+  ((krb5_context, krb5_rcache));
+    krb5_error_code ( *resolve)
+  ((krb5_context, krb5_rcache, char ));
+#endif /*0*/
+} krb5_rc_ops;
+
+
+/* from auth_con.h */
+struct _krb5_auth_context {
+    krb5_magic    magic;
+    krb5_address      * remote_addr;
+    krb5_address      * remote_port;
+    krb5_address      * local_addr;
+    krb5_address      * local_port;
+    krb5_keyblock     * keyblock;
+    krb5_keyblock     * local_subkey;
+    krb5_keyblock     * remote_subkey;
+
+    krb5_int32    auth_context_flags;
+    krb5_int32    remote_seq_number;
+    krb5_int32    local_seq_number;
+    krb5_authenticator *authentp;   /* mk_req, rd_req, mk_rep, ...*/
+    krb5_cksumtype  req_cksumtype;    /* mk_safe, ... */
+    krb5_cksumtype  safe_cksumtype;   /* mk_safe, ... */
+    krb5_pointer  i_vector;   /* mk_priv, rd_priv only */
+    krb5_rcache   rcache;
+    krb5_enctype      * permitted_etypes; /* rd_req */
+};
+typedef struct _krb5_auth_context * krb5_auth_context;
+
+
+/* the krb5 gss context that is stored in userland */
+typedef struct _krb5_gss_ctx_id_rec {
+   int initiate;  /* nonzero if initiating, zero if accepting */
+   u32 gss_flags;
+   int seed_init;
+   unsigned char seed[16];
+   krb5_principal here;
+   krb5_principal there;
+   krb5_keyblock *subkey;
+   int signalg;
+   int cksum_size;
+   int sealalg;
+   krb5_keyblock *enc;
+   krb5_keyblock *seq;
+   krb5_timestamp endtime;
+   krb5_flags krb_flags;
+   /* XXX these used to be signed.  the old spec is inspecific, and
+      the new spec specifies unsigned.  I don't believe that the change
+      affects the wire encoding. */
+   krb5_ui_4 seq_send;
+   krb5_ui_4 seq_recv;
+   void *seqstate;
+   int established;
+   int big_endian;
+   krb5_auth_context auth_context;
+   GSS_OID *mech_used;
+   int nctypes;
+   krb5_cksumtype *ctypes;
+} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t;
+
+/* from mit kerberos 5 ../lib/gssapi/mechglue/mglueP.h */
+typedef struct gss_union_ctx_id_t {
+  GSS_OID     mech_type;
+  GSS_CTX_ID_T    internal_ctx_id;
+} gss_union_ctx_id_desc, *gss_union_ctx_id_t;
+
+/* expose the cacheent */
+#define c_ctx(c)  (struct gss_ctx_cacheent *)((gss_union_ctx_id_t)c->data)->internal_ctx_id.data
+
+/* expose the kerberos ctx in the cacheent */
+#define k_ctx(c) (c_ctx(c))->gcc_ctx
+
+#define KG_TOK_SIGN_MSG   0x0101
+#define KG_TOK_SEAL_MSG   0x0201
+#define KG_TOK_MIC_MSG    0x0101
+#define KG_TOK_WRAP_MSG   0x0201
+
+enum sgn_alg {
+  SGN_ALG_DES_MAC_MD5           = 0x0000,
+  SGN_ALG_MD2_5                 = 0x0001,
+  SGN_ALG_DES_MAC               = 0x0002,
+  SGN_ALG_3     = 0x0003, /* not published */
+  SGN_ALG_HMAC_MD5              = 0x0011, /* microsoft w2k; no support */
+  SGN_ALG_HMAC_SHA1_DES3_KD     = 0x0004
+};
+enum seal_alg {
+  SEAL_ALG_NONE            = 0xffff,
+  SEAL_ALG_DES             = 0x0000,
+  SEAL_ALG_1       = 0x0001, /* not published */
+  SEAL_ALG_MICROSOFT_RC4   = 0x0010, /* microsoft w2k; no support */
+  SEAL_ALG_DES3KD          = 0x0002
+};
+
+#define RSA_MD5_CKSUM_LENGTH 16
+
+/* rsa-md4-des-k */
+#define CKSUMTYPE_RSA_MD5 0x0007
+#define CKSUMTYPE_RSA_MD5_DES 0x0008
+#define CKSUMTYPE_NIST_SHA  0x0009
+#define CKSUMTYPE_HMAC_SHA1_DES3  0x000c
+
+#define KG_USAGE_SEAL 22
+#define KG_USAGE_SIGN 23
+#define KG_USAGE_SEQ  24
+
+/* from gssapi_err_krb5.h */
+#define KG_CCACHE_NOMATCH                        (39756032L)
+#define KG_KEYTAB_NOMATCH                        (39756033L)
+#define KG_TGT_MISSING                           (39756034L)
+#define KG_NO_SUBKEY                             (39756035L)
+#define KG_CONTEXT_ESTABLISHED                   (39756036L)
+#define KG_BAD_SIGN_TYPE                         (39756037L)
+#define KG_BAD_LENGTH                            (39756038L)
+#define KG_CTX_INCOMPLETE                        (39756039L)
+#define KG_CONTEXT                               (39756040L)
+#define KG_CRED                                  (39756041L)
+#define KG_ENC_DESC                              (39756042L)
+#define KG_BAD_SEQ                               (39756043L)
+#define KG_EMPTY_CCACHE                          (39756044L)
+#define KG_NO_CTYPES                             (39756045L)
+
+
+/* from gssapi_err_generic.h */
+#define G_BAD_SERVICE_NAME                       (-2045022976L)
+#define G_BAD_STRING_UID                         (-2045022975L)
+#define G_NOUSER                                 (-2045022974L)
+#define G_VALIDATE_FAILED                        (-2045022973L)
+#define G_BUFFER_ALLOC                           (-2045022972L)
+#define G_BAD_MSG_CTX                            (-2045022971L)
+#define G_WRONG_SIZE                             (-2045022970L)
+#define G_BAD_USAGE                              (-2045022969L)
+#define G_UNKNOWN_QOP                            (-2045022968L)
+#define G_NO_HOSTNAME                            (-2045022967L)
+#define G_BAD_HOSTNAME                           (-2045022966L)
+#define G_WRONG_MECH                             (-2045022965L)
+#define G_BAD_TOK_HEADER                         (-2045022964L)
+#define G_BAD_DIRECTION                          (-2045022963L)
+#define G_TOK_TRUNC                              (-2045022962L)
+#define G_REFLECT                                (-2045022961L)
+#define G_WRONG_TOKID                            (-2045022960L)
+
+#define KV5M_PRINCIPAL                           (-1760647423L)
+#define KV5M_KEYBLOCK                            (-1760647421L)
+#define KV5M_CHECKSUM                            (-1760647420L)
+#define KV5M_ADDRESS                             (-1760647390L)
+#define KV5M_AUTHENTICATOR                       (-1760647410L)
+#define KV5M_AUTH_CONTEXT                        (-1760647383L)
+#define KV5M_AUTHDATA                            (-1760647414L)
+#define KV5M_GSS_OID                             (-1760647372L)
+#define KV5M_GSS_QUEUE                           (-1760647371L)
+
+#define g_OID_equal(o1,o2) \
+   (((o1)->len == (o2)->len) && \
+    (memcmp((o1)->data,(o2)->data,(int) (o1)->len) == 0))
+
+
+#define krb5_princ_realm(context, princ) (&(princ)->realm)
+#define krb5_princ_size(context, princ) (princ)->length
+#define krb5_princ_component(context, princ,i) ((princ)->data + i)
+
+ /* per Kerberos v5 protocol spec crypto types from the wire. 
+ * these get mapped to linux kernel crypto routines.  
+ */
+#define ENCTYPE_NULL            0x0000
+#define ENCTYPE_DES_CBC_CRC     0x0001  /* DES cbc mode with CRC-32 */
+#define ENCTYPE_DES_CBC_MD4     0x0002  /* DES cbc mode with RSA-MD4 */
+#define ENCTYPE_DES_CBC_MD5     0x0003  /* DES cbc mode with RSA-MD5 */
+#define ENCTYPE_DES_CBC_RAW     0x0004  /* DES cbc mode raw */
+/* XXX deprecated? */
+#define ENCTYPE_DES3_CBC_SHA    0x0005  /* DES-3 cbc mode with NIST-SHA */
+#define ENCTYPE_DES3_CBC_RAW    0x0006  /* DES-3 cbc mode raw */
+#define ENCTYPE_DES_HMAC_SHA1   0x0008
+#define ENCTYPE_DES3_CBC_SHA1   0x0010
+#define ENCTYPE_UNKNOWN         0x01ff
+/* local crud */
+/* marc's DES-3 with 32-bit length */
+#define ENCTYPE_LOCAL_DES3_HMAC_SHA1 0x7007
+
+#define CKSUMTYPE_CRC32         0x0001
+#define CKSUMTYPE_RSA_MD4       0x0002
+#define CKSUMTYPE_RSA_MD4_DES   0x0003
+#define CKSUMTYPE_DESCBC        0x0004
+/* des-mac-k */
+/* rsa-md4-des-k */
+
+/* this is the structure that maps between kerberos v5 keytypes and 
+ * linux kernel crypto transforms.
+ */
+
+
+
+
+/* function prototypes */
+
+u32 g_verify_token_header(
+     GSS_OID *mech,
+     int *body_size,
+     unsigned char **buf_in,
+     int tok_type,
+     int toksize);
+
+int g_token_size(
+     GSS_OID *mech,
+     unsigned int body_size);
+
+void g_make_token_header(
+     GSS_OID *mech,
+     int body_size,
+     unsigned char **buf,
+     int tok_type);
+
+u32 g_order_check(
+     void **vqueue, 
+     u32 seqnum);
+
+krb5_error_code
+krb5_ser_pack_bytes(
+    krb5_octet   *ostring,
+    size_t  osize,
+    krb5_octet   *  *bufp,
+    size_t   *remainp);
+
+krb5_error_code
+krb5_ser_unpack_bytes(
+    krb5_octet   *istring,
+    size_t  isize,
+    krb5_octet   *  *bufp,
+    size_t   *remainp);
+
+krb5_error_code
+krb5_ser_pack_int32(
+    krb5_int32    iarg,
+    krb5_octet     *  *bufp,
+    size_t     *remainp);
+
+krb5_error_code
+krb5_ser_unpack_int32(
+    krb5_int32   *intp,
+    krb5_octet   *  *bufp,
+    size_t   *remainp);
+
+u32 g_queue_size(
+    void *vqueue, 
+    size_t *sizep);
+
+u32
+g_queue_internalize(
+    void **vqueue, 
+		unsigned char **buf, 
+		size_t *lenremain);
+
+krb5_error_code
+krb5_principal_skip(
+    krb5_octet    **buffer,
+    size_t    *lenremain);
+
+krb5_error_code
+krb5_principal_size(
+    krb5_context  kcontext,
+    krb5_pointer  arg,
+    size_t    *sizep);
+
+krb5_error_code
+krb5_keyblock_size(
+    krb5_context  kcontext,
+    krb5_pointer  arg,
+    size_t    *sizep);
+
+krb5_error_code
+krb5_keyblock_internalize(
+    krb5_context  kcontext,
+    krb5_pointer  *argp,
+    krb5_octet    **buffer,
+    size_t    *lenremain);
+
+void
+krb5_free_keyblock(
+     krb5_context context,
+     register krb5_keyblock *key);
+
+krb5_error_code
+kg_oid_internalize(
+    krb5_context  kcontext,
+    krb5_pointer  *argp,
+    krb5_octet    **buffer,
+    size_t    *lenremain);
+
+krb5_error_code
+kg_queue_internalize(
+    krb5_context  kcontext,
+    krb5_pointer  *argp,
+    krb5_octet    **buffer,
+    size_t    *lenremain);
+
+krb5_error_code
+kg_ctx_internalize(
+    krb5_context  kcontext,
+    krb5_pointer  *argp,
+    krb5_octet    **buffer,
+    size_t    *lenremain);
+
+void
+print_krb5_gss_ctx_id_rec(
+    krb5_gss_ctx_id_t ctx);
+
+u32
+k5_gss_import_sec_context(
+        u32    *min_status,
+        GSS_BUFFER_T   *inbuf,
+        void  **ctx_handle);
+
+void 
+gss_clear_ctx_map(struct gss_ctx_mapping *map);
+
+int 
+k5_get_blocksize(
+	krb5_enctype enctype,
+	size_t *blocksize);
+
+int 
+k5_get_checksum_length(
+	krb5_cksumtype cksmtype, 
+	size_t *length);
+
+int 
+find_digest(krb5_cksumtype type);
+
+int
+find_enctype(krb5_enctype enctype);
+
+krb5_error_code 
+krb5_c_make_checksum(
+	krb5_context context,
+	krb5_cksumtype cksumtype,
+	krb5_keyblock *key,
+	krb5_keyusage usage,
+	krb5_data *input,
+	krb5_checksum *cksum);
+
+u32
+kg_seal(
+	krb5_context context,
+	u32 *minor_status,
+	GSS_CTX_ID_T *context_handle,
+	int conf_req_flag,
+	int qop_req,
+	GSS_BUFFER_T *input_message_buffer,
+	int *conf_state,
+	GSS_BUFFER_T *output_message_buffer,
+	int toktype);
+
+u32
+kg_unseal(
+    u32 *minor_status,
+    GSS_CTX_ID_T * context_handle,
+    GSS_BUFFER_T *input_token_buffer,
+    GSS_BUFFER_T * message_buffer,
+    int *conf_state,
+    int *qop_state,
+    int toktype);
+
+u32
+gss_k5encrypt(
+     krb5_keyblock *key,
+     int usage,
+     krb5_pointer iv,
+     krb5_pointer in,
+     krb5_pointer out,
+     int length);
+
+u32
+gss_k5decrypt(
+     krb5_keyblock *key,
+     int usage,
+     krb5_pointer iv,
+     krb5_pointer in,
+     krb5_pointer out,
+     int length);
+
+krb5_error_code
+kg_make_seq_num(
+     krb5_keyblock *key,
+     int direction,
+     krb5_int32 seqnum,
+     unsigned char *cksum,
+     unsigned char *buf);
+
+krb5_error_code kg_get_seq_num(
+     krb5_keyblock *key,
+     unsigned char *cksum,
+     unsigned char *buf,
+     int *direction,
+     krb5_int32 *seqnum);
--- clean/net/sunrpc/sched.c	Tue Feb 26 12:00:35 2002
+++ dirty/net/sunrpc/sched.c	Mon Feb 25 12:08:45 2002
@@ -718,12 +718,6 @@
 		__rpc_remove_wait_queue(task);
 		spin_unlock_bh(&rpc_queue_lock);
 
-	dprintk("RPC:__rpc_schedule: flavor %d current [%d:%d] proxy [%d:%d]\n ",
-         task->tk_client->cl_auth->au_ops->au_flavor, current->uid, 
-         current->gid,task->tk_client->cl_auth->proxy_uid,
-         task->tk_client->cl_auth->proxy_gid );
-	dprintk("RPC:__rpc_schedule: cred: %p\n",task->tk_msg.rpc_cred);
-
 		__rpc_execute(task);
 
 		if (++count >= 200 || current->need_resched) {
--- clean/net/sunrpc/stats.c	Tue Dec  7 13:03:12 1999
+++ dirty/net/sunrpc/stats.c	Mon Feb 25 12:08:45 2002
@@ -13,6 +13,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -23,6 +24,10 @@
 
 #define RPCDBG_FACILITY	RPCDBG_MISC
 
+#ifdef CONFIG_SUNRPC_GSS
+extern void gss_svc_ctx_init(void);
+#endif /* CONFIG_SUNRPC_GSS */
+
 static struct proc_dir_entry	*proc_net_rpc = NULL;
 
 /*
@@ -189,6 +194,9 @@
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
 #endif
+#ifdef CONFIG_SUNRPC_GSS
+	gss_svc_ctx_init();
+#endif /* CONFIG_SUNRPC_GSS */
 	rpc_proc_init();
 	return 0;
 }
--- clean/net/sunrpc/auth.c	Tue Feb 26 12:00:35 2002
+++ dirty/net/sunrpc/auth.c	Mon Feb 25 12:08:45 2002
@@ -193,22 +193,19 @@
  * rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
  */
 static struct rpc_cred *
-rpcauth_lookup_credcache(struct rpc_task *task)
+rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags,struct rpc_task *task)
 {
+/*
 	struct rpc_auth *auth = task->tk_auth;
 	int taskflags = task->tk_flags;
+*/
 	struct rpc_cred	**q, *cred = NULL;
 	int		nr = 0;
 
-  dprintk("RPC: auth->proxy_uid/gid [%d:%d]\n",auth->proxy_uid,auth->proxy_gid);
-
-  if (taskflags & RPC_TASK_PROXYCREDS)
-    dprintk("RPC: rpcauth_lookup_credcache found RPC_TASK_PROXYCREDS \n");
+  if (taskflags & RPC_TASK_MACHINE_CREDS)
+    dprintk("RPC: rpcauth_lookup_credcache found RPC_TASK_MACHINE_CREDS \n");
 
-  if ((auth->proxy_uid != -1) && (current->uid == 0)) {
-    nr = auth->proxy_uid & RPC_CREDCACHE_MASK;
-    dprintk("RPC: rpcauth_lookup_credcache using PROXY uid nr %d\n",nr);
-  } else if (!(taskflags & RPC_TASK_ROOTCREDS)) {
+	if (!(taskflags & RPC_TASK_ROOTCREDS)) {
 		nr = current->uid & RPC_CREDCACHE_MASK;
     dprintk("RPC: rpcauth_lookup_credcache using current uid nr %d \n",nr);
   }
@@ -219,8 +216,9 @@
 	spin_lock(&rpc_credcache_lock);
 	q = &auth->au_credcache[nr];
 	while ((cred = *q) != NULL) {
+
 		if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
-		    auth->au_ops->crmatch(cred, taskflags,auth->proxy_uid,auth->proxy_gid)) {
+		    auth->au_ops->crmatch(cred, taskflags)) {
 			*q = cred->cr_next;
 			break;
 		}
@@ -229,6 +227,8 @@
 	spin_unlock(&rpc_credcache_lock);
 
 	if (!cred) {
+		if (!task)
+			return NULL;
 		cred = auth->au_ops->crcreate(task);
 #ifdef RPC_DEBUG
 		if (cred)
@@ -236,7 +236,7 @@
 #endif
 	}
 
-	/* XXX: ANDROS: why insert into cred cache if found in above while loop? */
+	/* XXX:  why insert into cred cache if found in above while loop? */
 	if (cred)
 		rpcauth_insert_credcache(auth, cred);
 
@@ -269,11 +269,9 @@
 
 
 struct rpc_cred *
-rpcauth_lookupcred(struct rpc_task *task)
+rpcauth_lookupcred(struct rpc_auth *auth, int taskflags,struct rpc_task *task)
 {
-	dprintk("RPC:     looking up %s cred\n",
-		task->tk_auth->au_ops->au_name);
-	return rpcauth_lookup_credcache(task);
+	return rpcauth_lookup_credcache(auth,taskflags,task);
 }
 
 struct rpc_cred *
@@ -285,7 +283,7 @@
 		task->tk_pid, task->tk_auth->au_ops->au_name);
 
 	dprintk("RPC: bindcred calling lookup_credcache\n");
-	task->tk_msg.rpc_cred = rpcauth_lookup_credcache(task);
+	task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth,task->tk_flags,task);
 
 	dprintk("RPC: bindcred returning. cred %p \n",task->tk_msg.rpc_cred);
 
@@ -301,7 +299,7 @@
 {
 	dprintk("RPC:     matching %s cred %d\n",
 		auth->au_ops->au_name, taskflags);
-	return auth->au_ops->crmatch(cred, taskflags,auth->proxy_uid, auth->proxy_gid);
+	return auth->au_ops->crmatch(cred, taskflags);
 }
 
 void
@@ -349,7 +347,6 @@
 rpcauth_marshcred(struct rpc_task *task, u32 *p)
 {
 	struct rpc_auth	*auth = task->tk_auth;
-
 	dprintk("RPC: %4d marshaling %s cred %p\n",
 		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
 	return auth->au_ops->crmarshal(task, p,
--- clean/net/sunrpc/auth_null.c	Tue Feb 26 12:00:35 2002
+++ dirty/net/sunrpc/auth_null.c	Mon Feb 25 12:08:45 2002
@@ -29,7 +29,6 @@
 	auth->au_rslack = 2;
 	auth->au_ops = &authnull_ops;
 	auth->au_expire = 1800 * HZ;
-  auth->proxy_uid = auth->proxy_gid = -1;
 	rpcauth_init_credcache(auth);
 
 	return (struct rpc_auth *) auth;
@@ -73,11 +72,10 @@
  * Match cred handle against current process
  */
 static int
-nul_match(struct rpc_cred *cred, int taskflags,u32 proxy_uid,u32 proxy_gid)
+nul_match(struct rpc_cred *cred, int taskflags)
 {
 	return 1;
-}
-
+}  
 /*
  * Marshal credential.
  */
--- clean/net/sunrpc/auth_unix.c	Tue Feb 26 12:00:35 2002
+++ dirty/net/sunrpc/auth_unix.c	Mon Feb 25 12:08:45 2002
@@ -45,8 +45,6 @@
 	auth->au_rslack = 2;	/* assume AUTH_NULL verf */
 	auth->au_expire = UNX_CRED_EXPIRE;
 	auth->au_ops = &authunix_ops;
-  auth->proxy_uid = auth->proxy_gid = -1;
-
 	rpcauth_init_credcache(auth);
 
 	return auth;
@@ -139,7 +137,7 @@
  * request root creds (e.g. for NFS swapping).
  */
 static int
-unx_match(struct rpc_cred *rcred, int taskflags,u32 proxy_uid,u32 proxy_gid)
+unx_match(struct rpc_cred *rcred, int taskflags)
 {
 	struct unx_cred	*cred = (struct unx_cred *) rcred;
 	int		i;
--- clean/net/sunrpc/auth_gss.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/auth_gss.c	Mon Feb 25 12:12:31 2002
@@ -0,0 +1,593 @@
+/*
+ * linux/net/sunrpc/auth_gss.c
+ *
+ * RPCSEC_GSS client authentication.
+ * 
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Dug Song       <dugsong@monkey.org>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: rpcsec_gss_nfsv4patch3.0.patch,v 1.2 2002/02/26 17:39:36 andros Exp $
+ */
+
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+extern void rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred);
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_AUTH
+#endif
+
+#define NFS_NGROUPS	16
+
+#define GSS_CRED_EXPIRE		(60 * HZ)	/* XXX */
+#define GSS_CRED_SLACK		1024		/* XXX */
+#define GSS_VERF_SLACK		512		/* XXX */
+
+/* NOTE! this define must match the gssd define
+* as it is passed to gssd to signal the use of
+* machine creds */
+
+#define CA_RUN_AS_MACHINE  0x00000200 
+/* dump the buffer in `emacs-hexl' style */
+#define isprint(c)      ((c > 0x1f) && (c < 0x7f))
+
+void
+print_hexl(u32 *p, u_int length, u_int offset)
+{
+	u_int i, j, jm;
+	u8 c, *cp;
+	
+	dprintk("RPC: print_hexl: length %d\n",length);
+	dprintk("\n");
+	cp = (u8 *) p;
+	
+	for (i = 0; i < length; i += 0x10) {
+		dprintk("  %04x: ", (u_int)(i + offset));
+		jm = length - i;
+		jm = jm > 16 ? 16 : jm;
+		
+		for (j = 0; j < jm; j++) {
+			if ((j % 2) == 1)
+				dprintk("%02x ", (u_int)cp[i+j]);
+			else
+				dprintk("%02x", (u_int)cp[i+j]);
+		}
+		for (; j < 16; j++) {
+			if ((j % 2) == 1)
+				dprintk("   ");
+			else
+				dprintk("  ");
+		}
+		dprintk(" ");
+		
+		for (j = 0; j < jm; j++) {
+			c = cp[i+j];
+			c = isprint(c) ? c : '.';
+			dprintk("%c", c);
+		}
+		dprintk("\n");
+	}
+}
+
+static int
+xdr_encode_gss_init_arg(struct rpc_rqst *req, u32 *p,
+			struct xdr_netobj *argp)
+{
+	dprintk("RPC: xdr_encode_gss_init_arg (%p:%d)\n",
+		argp->data, argp->len);
+	
+	p = xdr_encode_netobj(p, argp);
+	
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+xdr_decode_gss_init_res(struct rpc_rqst *req, u32 *p,
+			struct rpc_gss_init_res *resp)
+{
+	p = xdr_decode_netobj(p, &resp->gr_ctx);
+	if(!p) return -EIO;
+
+	resp->gr_major = (u32) ntohl(*p++);
+	resp->gr_minor = (u32) ntohl(*p++);
+	resp->gr_win = (u32) ntohl(*p++);
+	p = xdr_decode_netobj(p, &resp->gr_token);
+	if(!p) return -EIO;
+
+	dprintk("RPC: xdr_decode_gss_init_res() = "
+		"(%p:%d, %d, %d, %d, %p:%d)\n",
+		resp->gr_ctx.data, resp->gr_ctx.len,
+		resp->gr_major, resp->gr_minor, resp->gr_win,
+		resp->gr_token.data, resp->gr_token.len);
+#if 0	
+	if (!xdr_ressize_check(req, p))
+		return -EIO;
+#endif
+	return 0;
+}	
+
+static struct rpc_auth *
+gss_create(struct rpc_clnt *clnt)
+{
+	struct rpc_auth	*auth;
+
+	dprintk("RPC: creating GSS authenticator for client %p\n", clnt);
+	if (!(auth = (struct rpc_auth *) rpc_allocate(0, sizeof(*auth))))
+		return NULL;
+	auth->au_cslack = GSS_CRED_SLACK;
+	auth->au_rslack = GSS_VERF_SLACK;
+	auth->au_expire = GSS_CRED_EXPIRE;
+	auth->au_ops = &authgss_ops;
+
+	rpcauth_init_credcache(auth);
+
+	return auth;
+}
+
+/* XXX - finish */
+static void
+gss_destroy(struct rpc_auth *auth)
+{
+	dprintk("RPC: destroying GSS authenticator %p\n", auth);
+	/* If we have saved contexts, tell server to destroy them. */
+
+	/* Destroy our local contexts. */
+	rpcauth_free_credcache(auth);
+
+  dprintk("RPC: gss_destroy calling rpc_free on auth %p\n",auth);
+	rpc_free(auth);
+}
+
+static void
+gss_destroy_cred(struct rpc_cred *rc)
+{
+	struct gss_cred *cred = (struct gss_cred *)rc;
+
+	dprintk("RPC: gss_destroy_cred \n");
+  if(cred->gc_service_name.len > 0){
+		rpc_free(cred->gc_service_name.data);
+    cred->gc_service_name.len = 0;
+  }
+
+  if(cred->gc_ctx_id.len > 0){
+		rpc_free(cred->gc_ctx_id.data);
+    cred->gc_ctx_id.len = 0;
+  }
+
+	if(cred->gc_cred.gc_ctx.len > 0){
+		rpc_free(cred->gc_cred.gc_ctx.data);
+	  cred->gc_cred.gc_ctx.len = 0;
+  }
+
+	gss_clear_ctx_map(&cred->gc_ctx_map);
+	rpc_free(cred);
+}
+
+/* XXX need to receive service from rpc program */
+#define SERVICE_NAME	"nfs"
+
+static struct rpc_cred *
+gss_create_cred(struct rpc_task *task)
+{
+	struct gss_cred	*cred;
+	struct rpc_gss_init_res res;
+	u32		maj_stat = 0, min_stat = 0, ret_flags;
+	GSS_BUFFER_T	recv_token, send_token;
+	kxdrproc_t	save_encode, save_decode;
+	struct rpc_cred *save_cred;
+	GSS_OID mech;
+	int flags = 0;
+
+	if (!(cred = (struct gss_cred *) rpc_allocate(task->tk_flags,
+						      sizeof(*cred))))
+		return NULL;
+
+	memset(cred, 0, sizeof(*cred));
+	cred->gc_count = 0;
+	cred->gc_flags = RPCAUTH_CRED_UPTODATE;
+
+	dprintk("RPC:      allocating GSS cred for uid %d gid %d\n",
+				current->uid, current->gid);
+	cred->gc_uid = current->uid;
+
+	cred->gc_established = 0;
+	
+	INIT_LIST_HEAD(&cred->gc_ctx_map.gss_ctx_cache);	
+	rwlock_init(&cred->gc_ctx_map.lock);
+		
+	if (task->tk_client->cl_server == NULL ||
+	    strcmp(task->tk_client->cl_server, "localhost") == 0) {
+		cred->gc_service_name.len = sizeof(SERVICE_NAME);
+		cred->gc_service_name.data =
+			rpc_allocate(0, cred->gc_service_name.len);
+		memcpy(cred->gc_service_name.data, SERVICE_NAME,
+		       sizeof(SERVICE_NAME));
+	}
+	else {
+		cred->gc_service_name.len = sizeof(SERVICE_NAME) + 1 +
+			strlen(task->tk_client->cl_server);
+		cred->gc_service_name.data =
+			rpc_allocate(0, cred->gc_service_name.len);
+		sprintf(cred->gc_service_name.data, SERVICE_NAME "@%s",
+			task->tk_client->cl_server);
+	}
+	cred->gc_ctx_id.data = NULL;
+	cred->gc_ctx_id.len = 0;
+	
+	cred->gc_cred.gc_v = RPC_GSS_VERSION;
+	cred->gc_cred.gc_proc = RPC_GSS_PROC_INIT;
+	cred->gc_cred.gc_svc = RPC_GSS_SVC_NONE;	/* XXX - configure */
+
+	/* Set temporary credential for RPCSEC_GSS NULLPROC call. */
+	save_cred = task->tk_msg.rpc_cred;
+	task->tk_msg.rpc_cred = (struct rpc_cred *)cred;
+	rpcauth_insert_credcache(task->tk_auth, (struct rpc_cred *)cred);
+
+	/*
+	 * XXX - swap out the program's NULLPROC handlers directly,
+	 * since there is no clean way to prevent dispatch.
+	 */
+	save_encode = rpcproc_encode(task->tk_client, 0);
+	save_decode = rpcproc_decode(task->tk_client, 0);
+	rpcproc_encode(task->tk_client, 0) =
+		(kxdrproc_t) xdr_encode_gss_init_arg;
+	rpcproc_decode(task->tk_client, 0) =
+		(kxdrproc_t) xdr_decode_gss_init_res;
+	
+	memset(&res, 0, sizeof(res));
+	memset(&send_token, 0, sizeof(send_token));
+	memset(&recv_token, 0, sizeof(recv_token));
+	
+	/* specify default mechanism. note: this should be the mechanism
+	* negotiated by the secinfo call. 
+	*/
+  mech.len =0;
+	mech.data = NULL;
+
+	if(task->tk_flags & RPC_TASK_MACHINE_CREDS)
+            flags |= CA_RUN_AS_MACHINE;
+
+	for (;;) {
+		dprintk("RPC: gss_create_cred() calling init_sec_context()\n");
+		if (gssd_init_sec_context(cred->gc_uid,
+					  flags,
+					  &maj_stat,
+					  &min_stat,
+					  &cred->gc_ctx_id,
+					  &cred->gc_service_name,
+					  &mech,
+					  &recv_token,
+					  &send_token,
+					  &ret_flags) < 0)
+			break;
+		dprintk("RPC: after init_sec_context()\n");
+		if (recv_token.len > 0) {
+			printk("RPC: freeing recv_token\n");
+			rpc_free(recv_token.data);
+			memset(&recv_token, 0, sizeof(recv_token));
+		}
+		if (maj_stat != GSS_S_COMPLETE &&
+		    maj_stat != GSS_S_CONTINUE_NEEDED)
+			break;
+		
+		if (send_token.len > 0) {
+			printk("RPC: sending token (%p:%d)\n",
+				send_token.data, send_token.len);
+
+			/* Send token as NULLPROC argument. */
+			if (rpc_call(task->tk_client, 0,
+				     &send_token, &res, 0) < 0)
+				break;
+
+			/* Check results. */
+			if (res.gr_major != GSS_S_COMPLETE &&
+			    res.gr_major != GSS_S_CONTINUE_NEEDED)
+				break;
+
+			/* Save server gss_ctx_id and token. */
+			if (res.gr_ctx.len > 0) {
+				if (cred->gc_cred.gc_ctx.len > 0)
+					rpc_free(cred->gc_cred.gc_ctx.data);
+				cred->gc_cred.gc_ctx.data =
+					rpc_allocate(0, res.gr_ctx.len);
+				memcpy(cred->gc_cred.gc_ctx.data,
+				       res.gr_ctx.data, res.gr_ctx.len);
+				cred->gc_cred.gc_ctx.len = res.gr_ctx.len;
+			}
+			if (res.gr_token.len > 0) {
+				recv_token.data =
+					rpc_allocate(0, res.gr_token.len);
+				memcpy(recv_token.data,
+				       res.gr_token.data, res.gr_token.len);
+				recv_token.len = res.gr_token.len;
+			}
+			cred->gc_cred.gc_proc = RPC_GSS_PROC_CONTINUE_INIT;
+		}
+		if (maj_stat == GSS_S_COMPLETE) {
+			/* Context initialized! 
+			 * Import context from GSSD into client cred cache 
+			 */
+			if (!gss_get_context(&maj_stat,
+			                    &min_stat,
+			                    &cred->gc_ctx_map,
+			                    &cred->gc_ctx_id) < 0) {
+		 /* XXX if gss_get_context() fails here
+			* need to send gss_destroy_context to server ??
+			* retry???
+			*/
+				break;
+			}
+			dprintk("RPC: gss_create_cred: cred->gc_wire_verf.data %p len %d\n",
+			         cred->gc_wire_verf.data,cred->gc_wire_verf.len);
+			if (cred->gc_wire_verf.data != NULL) {
+				GSS_BUFFER_T bufin;
+				GSS_BUFFER_T bufout;
+				u32 seq,qop_state;
+
+				dprintk("RPC: gss_create_cred: preparing for VERIFICATION. gc_seq %d gr_win %d\n",
+            cred->gc_cred.gc_seq,res.gr_win); 
+				seq = htonl(res.gr_win);
+				bufin.data = (u8 *) &seq;
+				bufin.len = sizeof(seq);
+				bufout.data = (u8 *) cred->gc_wire_verf.data;
+				bufout.len = cred->gc_wire_verf.len;
+
+  			dprintk("RPC: VERIFICATION TOKEN WIRE TEXT: bufout.len %d \n",bufout.len);
+				print_hexl((u32 *)bufout.data,bufout.len,0);	
+  			dprintk("RPC: VERIFICATION INPUT TEXT: bufin.len %d \n",bufout.len);
+				print_hexl((u32 *)bufin.data,bufin.len,0);	
+
+				/* validate context handle */
+				if(!gss_validate_context(&cred->gc_ctx_id,&cred->gc_ctx_map)){
+					printk("auth_gss: invalid context handle.\n");
+					return(NULL);
+				}
+				if ((maj_stat = gss_verify_mic(&min_stat,&cred->gc_ctx_id, 
+                        &bufin, &bufout, &qop_state) < 0))
+
+					break;
+			}
+
+			/* Change phase to RPC data exchange. */
+			cred->gc_established = 1;
+			cred->gc_cred.gc_proc = RPC_GSS_PROC_DATA;
+			cred->gc_cred.gc_seq = 1;
+			cred->gc_win = res.gr_win;
+			break;
+		}
+	}
+	/* Disassociate temporary credentials. */
+	task->tk_msg.rpc_cred = save_cred;
+	rpcauth_remove_credcache(task->tk_auth, (struct rpc_cred *)cred);
+	
+	/* XXX - restore target program's original NULLPROC mappings. */
+	rpcproc_encode(task->tk_client, 0) = (kxdrproc_t) save_encode;
+	rpcproc_decode(task->tk_client, 0) = (kxdrproc_t) save_decode;
+
+	if (!cred->gc_established) {
+		printk("RPC: GSS context establishment failed.\n");
+		gss_destroy_cred((struct rpc_cred *)cred);
+    task->tk_status = -EACCES;
+		return NULL;
+	}
+	/* XXX - should check for service match. */
+	
+	dprintk("RPC: GSS context establishment succeeded.\n");
+	return (struct rpc_cred *) cred;
+}
+
+/*
+ * Match credentials against current process creds.
+ *
+ * XXX  this should be a lot more detailed compairson, perhaps a per
+ * mechanism check.
+ */
+static int
+gss_match(struct rpc_cred *rc, int taskflags)
+{
+	struct gss_cred *cred = (struct gss_cred *)rc;
+	
+  dprintk("RPC: gss_match using current->uid %d\n",current->uid);
+	return (cred->gc_uid == current->uid);
+}
+
+/*
+ * Marshal credentials.
+ * Maybe we should keep a cached credential for performance reasons.
+ */
+static u32 *
+gss_marshal(struct rpc_task *task, u32 *p, int ruid)
+{
+	struct gss_cred	*cred = (struct gss_cred *) task->tk_msg.rpc_cred;
+	u32		*base;
+	struct rpc_rqst *req = task->tk_rqstp;
+	struct rpc_clnt *clnt = task->tk_client;
+	struct rpc_xprt *xprt = clnt->cl_xprt;
+	u32             *verfbase = req->rq_svec[0].iov_base; 
+	u32             min_stat = 0,maj_stat = 0;
+	struct gss_ctx_cacheent *cep;
+	GSS_CTX_ID_T *ctx;
+	GSS_BUFFER_T    bufin,bufout;
+
+	dprintk("RPC: gss_marshal\n");
+	/* set verfbase to the beginning of the rpc header. see clnt.c 
+	* call_header(). 
+	* header starts with the xid and includes the credential.
+	*/
+	if(xprt->stream)
+		verfbase++;
+	/* Marshal credential. */
+	*p++ = htonl(RPC_AUTH_GSS);
+	base = p++;
+	*p++ = htonl((u32) cred->gc_cred.gc_v);
+	*p++ = htonl((u32) cred->gc_cred.gc_proc);
+	if(cred->gc_established == 1)
+		cred->gc_cred.gc_seq++;
+	*p++ = htonl((u32) cred->gc_cred.gc_seq);
+	*p++ = htonl((u32) cred->gc_cred.gc_svc);
+	p = xdr_encode_netobj(p, &cred->gc_cred.gc_ctx);
+	*base = htonl((p - base - 1) << 2);	/* cred length */
+
+	/* Marshal verifier. */
+	if (cred->gc_established) {
+		bufin.data = (u8 *)verfbase;
+		bufin.len = (p - verfbase) << 2;
+
+		/* set verifier flavor*/
+		*p++ = htonl(RPC_AUTH_GSS);
+
+		/* validate the context */
+		if(!gss_validate_context(&cred->gc_ctx_id,&cred->gc_ctx_map)){
+	        	printk("gss_marshal: INVALID GSS_CONTEXT\n");
+			return(NULL);
+		}
+
+		/* p now points at the verifier data which is a token
+		* returned by gss_get_mic()
+		*/
+		ctx = &cred->gc_ctx_id;
+		cep = c_ctx(ctx);
+
+		maj_stat = gss_get_mic(&min_stat, 
+			               &cred->gc_ctx_id, 
+				       cep->gcc_qop, 
+				       &bufin, &bufout);
+		if(maj_stat != 0){
+			printk("gss_marshal: gss_get_mic FAILED (%d:%d)\n",maj_stat,min_stat);
+			return(NULL);
+		}
+		p = xdr_encode_netobj(p, &bufout);
+		return p;
+	}else { /* Set NULL verifier */
+		*p++ = htonl(RPC_AUTH_NULL);
+		*p++ = 0;
+	}
+	return p;
+}
+
+/*
+ * Refresh credentials. XXX - finish
+ */
+static int
+gss_refresh(struct rpc_task *task)
+{
+	task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+	return task->tk_status = -EACCES;
+}
+
+static u32 *
+gss_validate(struct rpc_task *task, u32 *p)
+{
+	struct gss_cred *cred = NULL; 
+	u32		seq, qop_state;
+	GSS_BUFFER_T	bufin;
+	GSS_BUFFER_T	bufout;
+	u32		flav,len,min_status =0;
+	int             code = 0;
+
+	(struct rpc_cred *)cred = task->tk_msg.rpc_cred;
+	
+	dprintk("RPC: gss_validate \n");
+	/* verifier flavor */
+	flav = ntohl(*p++);
+
+/* XXX do we need RPC_AUTH_NULL as a valid flavor here?  does this
+ * code get hit during the init_sec/accept_sec context phase, or just
+ * during the data phase? i think RPC_AUTH_NULL should be removed here... */
+	if (flav != RPC_AUTH_GSS && flav != RPC_AUTH_NULL) {
+		printk("RPC: bad verf flavor: %ld\n", (unsigned long) flav);
+		return NULL;
+	}
+	dprintk("RPC: gss_validate: flavor %ld \n",(unsigned long)flav);
+
+	if ((len = ntohl(*p++)) > 400) {
+		printk("RPC: giant verf size: %ld\n", (unsigned long) len);
+		return NULL;
+	}
+	dprintk("RPC: gss_validate: len %ld\n", (unsigned long)len);
+	if(task->tk_msg.rpc_proc == 0){
+		/* save the on the wire verifier to validate last INIT phase packet
+		* after decode if the major status is GSS_S_COMPLETE */
+		if(!(cred->gc_wire_verf.data = (u8 *)rpc_allocate(0,len<<2)))
+			return NULL;
+		memcpy(cred->gc_wire_verf.data,(u8 *)p,len<<2);
+		cred->gc_wire_verf.len = len;  /*NOTE: kerberos uses u32 lengths!*/
+  dprintk("RPC: VERIFICATION WIRE TEXT: verf_len %d\n",cred->gc_wire_verf.len);
+	print_hexl((u32 *)cred->gc_wire_verf.data,cred->gc_wire_verf.len,0);	
+	}else{
+		cred->gc_wire_verf.data = (u8 *)NULL;
+		cred->gc_wire_verf.len = 0;
+	}
+		
+	/* DATA phase verifier */
+	if (cred->gc_established) {
+		seq = htonl(cred->gc_cred.gc_seq);
+		bufin.data = (u8 *) &seq;
+		bufin.len = sizeof(seq);
+		bufout.data = (u8 *) p;
+		bufout.len = len;
+		
+	/* validate context handle */
+	if(!gss_validate_context(&cred->gc_ctx_id,&cred->gc_ctx_map)){
+		printk("auth_gss: invalid context handle.\n");
+		return(NULL);
+	}
+	if ((code = gss_verify_mic(&min_status,&cred->gc_ctx_id, 
+                        &bufin, &bufout, &qop_state) < 0))
+		return NULL;
+	}
+	dprintk("RPC: GSS gss_validate: gss_verify_mic returns %d. skipping verifier: skipping %d bytes\n",code, XDR_QUADLEN(len));
+	task->tk_auth->au_rslack = XDR_QUADLEN(len) + 2;
+	return p + XDR_QUADLEN(len);
+}
+
+struct rpc_authops	authgss_ops = {
+	RPC_AUTH_GSS,
+#ifdef RPC_DEBUG
+	"RPCSEC_GSS",
+#endif
+	gss_create,
+	gss_destroy,
+	gss_create_cred,
+	gss_destroy_cred,
+	gss_match,
+	gss_marshal,
+	gss_refresh,
+	gss_validate
+};
--- clean/net/sunrpc/svcauth_gss.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/svcauth_gss.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,491 @@
+/*
+ *  linux/net/sunrpc/svcauth_gss.c
+ *
+ *  RPCSEC_GSS server authentication.
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Dug Song       <dugsong@monkey.org>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: rpcsec_gss_nfsv4patch3.0.patch,v 1.2 2002/02/26 17:39:36 andros Exp $
+ */
+
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/sunrpc/types.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/svcauth.h>
+#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+#include <linux/sunrpc/sched.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_AUTH
+#endif
+
+static int
+xdr_argsize_check(struct svc_rqst *req, u32 *p)
+{
+	struct svc_buf *buf = &req->rq_argbuf;
+  int len = p - buf->base;  /* amount used */
+	dprintk("RPC: xdr_argsize_check. buf->len %d buf->buflen %d, len %d\n",
+	             buf->len,buf->buflen,len);
+	return((buf->len = buf->buflen - len) > 0);
+}
+
+static int
+xdr_ressize_check(struct svc_rqst *req, u32 *p)
+{
+	struct svc_buf *buf = &req->rq_resbuf;
+	buf->len = p - buf->base;
+	dprintk("RPC: ressize_check p %p base %p len %d\n",
+		p, buf->base, buf->len);
+	return (buf->len <= buf->buflen);
+}
+	
+static u32 *
+xdr_decode_rpc_gss_cred(struct svc_rqst *req, u32 *p, struct rpc_gss_cred *gc)
+{
+
+	gc->gc_v = (u32) ntohl(*p++);
+	gc->gc_proc = (u32) ntohl(*p++);
+	gc->gc_seq = (u32) ntohl(*p++);
+	gc->gc_svc = (u32) ntohl(*p++);
+	p = xdr_decode_netobj(p, &gc->gc_ctx);
+
+	dprintk("RPC: xdr_decode_rpc_gss_cred() = "
+		"(%d, %d, %d, %d, %p:%d)\n",
+		gc->gc_v, gc->gc_proc, gc->gc_seq, gc->gc_svc,
+		gc->gc_ctx.data, gc->gc_ctx.len);
+	
+	if (!xdr_argsize_check(req, p))
+		return NULL;
+	return p;
+}
+
+static u32 *
+xdr_decode_gss_init_arg(struct svc_rqst *req, u32 *p,
+			struct xdr_netobj *argp)
+{
+	p = xdr_decode_netobj(p, argp);
+	
+	dprintk("RPC: xdr_decode_gss_init_arg() = (%p:%d)\n",
+		argp->data, argp->len);
+	
+	if (!xdr_argsize_check(req, p))
+		return NULL;
+	return p;
+}
+
+int
+xdr_encode_rpc_gss_init_res(struct svc_rqst *req, u32 *p,
+			    struct rpc_gss_init_res *resp)
+{
+
+	dprintk("RPC: xdr_encode_rpc_gss_init_res"
+		"(%p:%d, %d, %d, %d, %p:%d)\n",
+		resp->gr_ctx.data, resp->gr_ctx.len,
+		resp->gr_major, resp->gr_minor, resp->gr_win,
+		resp->gr_token.data, resp->gr_token.len);
+
+	p = xdr_encode_netobj(p, &resp->gr_ctx);
+	*p++ = (u32) htonl(resp->gr_major);
+	*p++ = (u32) htonl(resp->gr_minor);
+	*p++ = (u32) htonl(resp->gr_win);
+	p = xdr_encode_netobj(p, &resp->gr_token);
+
+	return xdr_ressize_check(req, p);
+}
+
+void
+svcauth_gss(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
+{
+	struct svc_buf	       *argp = &rqstp->rq_argbuf;
+	struct svc_buf	       *resp = &rqstp->rq_resbuf;
+	struct svc_cred	       *cred = &rqstp->rq_cred;
+	u32	uid, *bufp = argp->buf,*p,*rptr,credlen;
+	struct rpc_gss_cred	gc;
+	struct rpc_gss_init_res	gr;
+	GSS_BUFFER_T		input_token, client_name;
+	GSS_BUFFER_T		bufin, bufout;
+	u32			maj_stat =0,min_stat = 0,state = 0;
+	u32			ret_flags;
+	u32			win = 0;
+	unsigned char           rpchdrbuf[128];
+	int                     seq = 0;
+	
+	dprintk("RPC: svcauth_gss: argp->len %d\n",argp->len);
+	if (argp->len < 6) {
+		*statp = rpc_garbage_args;
+		return;
+	}
+	credlen = ntohl(*bufp++);	
+	dprintk("RPC: svcauth_gss. credlen %d\n",credlen);
+
+	if ((bufp = xdr_decode_rpc_gss_cred(rqstp, bufp, &gc)) == NULL) {
+		*statp = rpc_garbage_args;
+		return;
+	}
+
+	if (gc.gc_v != RPC_GSS_VERSION)
+		goto rejcred;
+	
+	/* Switch on RPCSEC_GSS phase. */
+	switch (gc.gc_proc) {
+
+	case RPC_GSS_PROC_DATA:
+		dprintk("RPC: RPCSEC_GSS_DATA\n");
+		if (rqstp->rq_proc == 0) {	/* NULLPROC */
+			printk("RPC: DATA state but NULLPROC: %d\n",
+			       rqstp->rq_proc);
+			*authp = rpc_prog_mismatch; /* XXX? */
+			return;
+		}
+		/* check service - todo */
+
+		/* check context handle - todo (done in gss_get_mic) */
+
+		/* Check verifier. Not a creation request, so expect 
+		 * RPC_AUTH_GSS verifier 
+		*/
+		dprintk("RPC: svcauth_gss: verifier flavor %d\n",ntohl(*bufp));
+		if(ntohl(*bufp) != RPC_AUTH_GSS){
+			printk("RPC: svcauth_gss: bad verifier flavor %d\n",ntohl(*bufp));
+			*authp = rpc_autherr_badverf;
+			return;
+		}
+		bufp++;
+
+		dprintk("RPC: svcauth_gss: verifier len %d\n",ntohl(*bufp));
+		/* get the verifier length (in bytes) */
+		bufout.len=ntohl(*bufp++);
+
+		/* get the verifier - for now, don't use bufp in get_mic call*/
+		if(!(bufout.data = (char *)rpc_allocate(0,bufout.len))){
+			printk("RPC: svcauth_gss: rpc_allocate failed\n");
+			*statp = rpc_system_err;
+			return;                              
+		}
+		memcpy(bufout.data,bufp,bufout.len);  
+    /* bump the xdr'ed argp buf pointer past the verifier*/
+		bufp += XDR_QUADLEN(bufout.len);
+
+    dprintk("RPC: bufout:\n");
+    print_hexl((u32 *)bufout.data,XDR_QUADLEN(bufout.len),0);     
+
+		/* reconstruct the rpc header */
+		rptr = (u32 *)rpchdrbuf;
+		memset(rpchdrbuf,0,128);
+		*rptr++ = rqstp->rq_xid;
+		*rptr++ = 0;   /* direction checked in svc_process */
+		*rptr++ = htonl(2);   /* rpc version checked in svc_process */
+		*rptr++ = htonl(rqstp->rq_prog);
+		*rptr++ = htonl(rqstp->rq_vers);
+		*rptr++ = htonl(rqstp->rq_proc);
+		*rptr++ = htonl(RPC_AUTH_GSS);
+		*rptr++ = htonl(credlen);
+		*rptr++ = htonl(gc.gc_v);
+		*rptr++ = htonl(gc.gc_proc);
+		*rptr++ = htonl(gc.gc_seq);
+		*rptr++ = htonl(gc.gc_svc);
+		*rptr++ = htonl(gc.gc_ctx.len);
+
+		if(gc.gc_ctx.len && (gc.gc_ctx.len < 79)){ /* 79 bytes left out of 128 */
+			dprintk("RPC: svcauth_gss: gc.gc_ctx.len %d XDR_QUADLEN %d\n",
+			          gc.gc_ctx.len,XDR_QUADLEN(gc.gc_ctx.len));
+			memcpy((char *)rptr,gc.gc_ctx.data,gc.gc_ctx.len);
+			rptr+= XDR_QUADLEN(gc.gc_ctx.len);
+		}
+	 	bufin.len = (unsigned char *)rptr - rpchdrbuf; 	
+		bufin.data = rpchdrbuf;
+
+		dprintk("RPC:svcauth_gss: reconstructed hdr len %d data:\n",bufin.len);
+		print_hexl((u32 *)bufin.data,XDR_QUADLEN(bufin.len),0);
+
+		    /* validate context handle */
+		if(!gss_svc_validate_context(&gc.gc_ctx)){
+			printk("svcauth_gss: invalid context handle\n");
+			*authp = rpc_autherr_badverf;
+                        return;
+		}
+
+		maj_stat = gss_verify_mic(&min_stat,
+		                         &gc.gc_ctx,
+		                         &bufin,
+		                         &bufout,
+                             &state);
+
+		rpc_free(bufout.data);
+
+
+		if(maj_stat != GSS_S_COMPLETE){
+			*authp = rpc_autherr_badverf;
+                        return;
+                }                                    
+		/* increment argbuf */
+		argp->len -= XDR_QUADLEN(bufp - argp->buf);
+		argp->buf = bufp;
+    dprintk("RPC: svcauth_gss: argp->len %d\n",argp->len);
+
+		/* check the cred sequence number - to do */
+
+		/* set the next verifier */
+		svc_putlong(resp, htonl(RPC_AUTH_GSS));
+
+
+		seq = htonl(gc.gc_seq);
+		bufin.data = (u8 *)&seq;
+		bufin.len = sizeof(seq);
+                memset(rpchdrbuf,0,128); /* XXX need 20 for sha1, 16 for md5 */
+		bufout.data = rpchdrbuf;
+		bufout.len = 0;  /*XXX set to bufout.data len */
+
+		/* validate context handle */
+		if(!gss_svc_validate_context(&gc.gc_ctx)){
+			printk("svcauth_gss: invalid context handle.\n");
+		        *authp = rpc_autherr_badverf;	
+			return;
+		}
+
+                maj_stat = gss_get_mic(&min_stat,
+                               &gc.gc_ctx,
+                               0,
+                               &bufin,
+                               &bufout);
+		if(maj_stat != GSS_S_COMPLETE){
+			*authp = rpc_autherr_badverf;
+                        return;
+                }                                    
+		p = resp->buf;
+
+		resp->buf = xdr_encode_netobj(resp->buf,&bufout);
+		resp->len += XDR_QUADLEN(bufout.len);
+
+		rqstp->rq_verfed = 1;
+		break;
+
+	case RPC_GSS_PROC_DESTROY:
+		dprintk("RPC: RPCSEC_GSS_DESTROY\n");
+		/* XXX - whack context here! */
+		/* deal with verifier... */
+
+		/* increment argbuf */
+		argp->len -= (bufp - argp->buf);
+		argp->buf = bufp;
+		break;
+
+	case RPC_GSS_PROC_INIT:
+	case RPC_GSS_PROC_CONTINUE_INIT:
+		if (rqstp->rq_proc != 0) {	/* NULLPROC */
+			dprintk("RPC: *INIT state but not NULLPROC: %d\n",
+			       rqstp->rq_proc);
+			goto rejcred;		/* XXX - ? */
+		}
+		/* creation request, thus a null verifier */
+		dprintk("RPC: svcauth_gss: verifier flavor %d\n",ntohl(*bufp));
+		if((ntohl(*bufp++) != RPC_AUTH_NULL) || (ntohl(*bufp++) != 0)){
+			printk("RPC: svcauth_gss: bad verifier flavor or length\n");
+			*authp = rpc_autherr_badverf;
+			return;
+		}
+	        /* increment argbuf */
+		argp->len -= (bufp - argp->buf);
+		argp->buf = bufp;
+		if (gc.gc_proc == RPC_GSS_PROC_INIT) {
+			dprintk("RPC: RPCSEC_GSS_INIT\n");
+			if (gc.gc_ctx.len != 0) {
+				dprintk("RPC: non-empty handle on initial context creation request\n");
+				goto rejcred;	/* XXX */
+			}
+		}
+		else {
+			dprintk("RPC: RPCSEC_GSS_CONTINUE_INIT\n");
+			if (gc.gc_ctx.len == 0) {
+				dprintk("RPC: expected non-empty handle in continue\n");
+				goto rejcred;	/* XXX */
+			}
+		}
+		/* Decode arguments. */
+		if (!xdr_decode_gss_init_arg(rqstp, bufp, &input_token)) {
+			goto rejcred;	/* XXX */
+		}
+		if (gssd_accept_sec_context(&gr.gr_major,
+					    &gr.gr_minor,
+					    &gc.gc_ctx,
+					    &input_token,
+					    &client_name,
+					    &gr.gr_token,
+					    &ret_flags) < 0)
+			goto rejcred;	/* XXX */
+
+		if (gr.gr_major != GSS_S_COMPLETE &&
+		    gr.gr_major != GSS_S_CONTINUE_NEEDED) {
+			dprintk("RPC: accept_sec_context failed!\n");
+			goto rejcred;	/* XXX */
+		}
+		/* Accepted security context. */
+		dprintk("RPC: accepted context, ctx (%p:%d) token (%p:%d)\n",
+			gc.gc_ctx.data,gc.gc_ctx.len,gr.gr_token.data,gr.gr_token.len);
+
+		/* Import security context from GSSD. */
+		if (gss_svc_get_context(&gr.gr_major,
+		                    &gr.gr_minor,
+				    &gc.gc_ctx)< 0)
+			goto rejcred;	/* XXX */
+		dprintk("RPC: imported context, ctx.len=%d\n",
+			gc.gc_ctx.len);
+		*authp = rpc_auth_ok;
+	
+		/* Convert client name, fill in rpc_cred struct with uid */
+		if (gssd_name_to_uid(&client_name, &uid) < 0) {
+			*statp = rpc_system_err;
+			return;
+		}
+		cred->cr_uid = (uid_t) uid;
+		gr.gr_win = 5;
+		gr.gr_ctx.len = gc.gc_ctx.len;
+		gr.gr_ctx.data = gc.gc_ctx.data;
+		if (gr.gr_major == GSS_S_COMPLETE) {
+
+			/* Put GSS verifier. */
+                       
+			win = htonl(gr.gr_win);
+			bufin.data = (unsigned char *)&win;
+			bufin.len = sizeof(win);
+		
+			/* xdr verifier flavor */
+			svc_putlong(resp, htonl(RPC_AUTH_GSS));
+
+			/* validate context handle */
+			if(!gss_svc_validate_context(&gc.gc_ctx)){
+				printk("svcauth_gss: invalid context handle\n");
+				*authp = rpc_autherr_badverf; /*XXX*/
+			}
+
+			if(gss_get_mic(&gr.gr_minor,
+			              &gc.gc_ctx,
+			              0,
+			              &bufin,
+			              &bufout))
+				goto rejcred;	/* XXX */
+
+			dprintk("RPC:svcauth_gss after get_mic. bufout.len %d\n",bufout.len);
+			print_hexl((u32 *)bufout.data,XDR_QUADLEN(bufout.len),0);
+
+			/* NOTE: 
+			* GSS_BUFFER_T lengths count number of u8s
+			* svc_buf lengths count number of u32s
+ 			*/
+
+			/* xdr verifier */
+			p = resp->buf;
+			resp->buf = xdr_encode_netobj(resp->buf,&bufout);
+			resp->len += resp->buf-p;
+
+			rqstp->rq_verfed = 1;
+		}
+		else {
+			/* Put NULL verifier */
+			rqstp->rq_verfed = 1;
+			svc_putlong(resp, RPC_AUTH_NULL);
+			svc_putlong(resp, 0);
+		}
+		/* save room for the RPC ACCEPT state, set in svc_process */
+		bufp = (u32 *)rqstp->rq_resp;
+		bufp++;
+
+		/*
+		 * XXX - Save results to marshal later as NULLPROC results,
+		 * faking the decode stage for our dispatcher below.
+		 */
+		dprintk("RPC setting gr ctx (%p:%d) maj:min (%d:%d) win %d token (%p:%d)\n",
+		        gr.gr_ctx.data,gr.gr_ctx.len, gr.gr_major,gr.gr_minor,gr.gr_win,
+		        gr.gr_token.data,gr.gr_token.len);
+
+		*(struct rpc_gss_init_res *)bufp = gr;
+		dprintk("RPC: bufp:\n");
+		print_hexl(bufp,7,0);
+		return;
+		
+	default:
+		dprintk("RPC: unknown RPCSEC_GSS phase %d\n", gc.gc_proc);
+		goto rejcred;
+		break;
+	}
+	/* Put NULL verifier */
+	rqstp->rq_verfed = 1;
+#if 0
+	svc_putlong(resp, RPC_AUTH_NULL);
+	svc_putlong(resp, 0);
+#endif
+	return;
+	
+ rejcred:
+	*authp = rpc_autherr_rejectedcred;
+}
+
+int
+svcauth_gss_dispatch(struct svc_rqst *rqstp, u32 *statp)
+{
+	struct svc_procedure   *proc;
+	kxdrproc_t		xdr;
+
+	dprintk("RPC: svcauth_gss_dispatch: vers %d proc %d\n",
+		            rqstp->rq_vers, rqstp->rq_proc);
+
+	proc = rqstp->rq_procinfo;
+
+	/* XXX - NULLPROC decode stage handled above by svcauth_gss(). */
+	if (rqstp->rq_proc == 0) {
+		if (!xdr_encode_rpc_gss_init_res(rqstp, rqstp->rq_resbuf.buf,
+						 (struct rpc_gss_init_res *)
+						 rqstp->rq_resp))
+			*statp = rpc_system_err;
+		return 1;
+	}
+	/* Decode arguments. */
+	xdr = proc->pc_decode;
+	if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp)) {
+		dprintk("RPC: svcauth_gss_dispatch: can't decode arguments\n");
+		*statp = rpc_garbage_args;
+		return 1;
+	}
+	*statp = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+
+	/* Encode results. */
+	xdr = proc->pc_encode;
+	if (*statp == rpc_success &&
+	    xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
+		dprintk("RPC: svcauth_gss_dispatch: failed to encode reply\n");
+		*statp = rpc_system_err;
+	}
+	return 1;
+};
--- clean/net/sunrpc/Makefile	Tue Feb 26 12:00:35 2002
+++ dirty/net/sunrpc/Makefile	Mon Feb 25 12:08:45 2002
@@ -18,7 +18,7 @@
 
 obj-$(CONFIG_PROC_FS) += stats.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
-obj-$(CONFIG_SUNRPC_GSS) += auth_gss.o  svcauth_gss.o gss_cache.o gss_svc_cache.o gss_mic.o gss_union.o gss_generic_token.o gss_generic_ordering.o gss_k5serialize.o gss_k5ser.o gss_intern_ctx.o gss_util_crypto.o gss_k5cksum.o gss_k5hash_md5.o gss_k5seal.o gss_k5unseal.o gss_k5encrypt.o gss_k5util_seqnum.o gss_k5decrypt.o
+obj-$(CONFIG_SUNRPC_GSS) += auth_gss.o  svcauth_gss.o gss_cache.o gss_svc_cache.o gss_mic.o gss_union.o gss_generic_token.o gss_generic_ordering.o gss_k5serialize.o gss_k5ser.o gss_intern_ctx.o gss_util_crypto.o gss_k5cksum.o gss_k5hash_md5.o gss_k5seal.o gss_k5unseal.o gss_k5encrypt.o gss_k5util_seqnum.o gss_k5decrypt.o 
 
 obj-m  := $(O_TARGET)
 
--- clean/net/sunrpc/gss_cache.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_cache.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,285 @@
+/*
+ *  linux/net/sunrpc/gss_cache.c
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *  Dug Song       <dugsong@monkey.org>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/* import the krb5 gss context into the kernel for use with gss crypto
+ * routines.
+ * for now, only import the pieces of the context actively used by
+ * gss_verify_mic and gss_get_mic.
+ *
+ * typedef struct _krb5_gss_ctx_id_rec_kernel {
+ *    int initiate;
+ *    int seed_init;
+ *    unsigned char seed[16];
+ *    krb5_keyblock *subkey;
+ *    int sealalg;
+ *    krb5_keyblock *enc;
+ *    krb5_keyblock *seq;
+ *    krb5_timestamp endtime;
+ *    void *seqstate;
+ *    int established;
+ *    int big_endian;
+ *    GSS_OID *mech_used;
+ * } krb5_gss_ctx_id_rec_kernel, *krb5_gss_ctx_id__kernel_t;
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/auth_gss.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+/*
+ ***************** gss context cache functions *********************
+ *
+ * On the client, the gss_ctx_mapping structs  hang off the 
+ * rpc_clnt->cl_auth->au_credcache.
+ *
+ */
+
+/* Function: gss_ctx_alloc
+*
+* Description: allocate and initialize a gss_ctx_cacheent structure.
+*
+*/
+
+struct gss_ctx_cacheent *
+gss_ctx_alloc(void)
+{
+	struct gss_ctx_cacheent *p;
+
+	/* caller must not hold spinlock, since this routine can block */
+
+	if (!(p = (struct gss_ctx_cacheent *)rpc_allocate(0,sizeof(struct gss_ctx_cacheent))))
+		goto nomem;
+	dprintk("RPC: gss_ctx_alloc: returning ctx_cacheent %p\n", p);
+	memset(p,0,sizeof(struct gss_ctx_cacheent));
+out:
+	return p;
+nomem:
+	printk("RPC: gss_ctx_alloc: out of memory!\n");
+	p = NULL;
+	goto out;
+}
+
+void
+gss_ctx_free(struct gss_ctx_cacheent *p)
+{
+	dprintk("RPC: gss_ctx_free\n");
+	
+/* note: gss_destroy_cred free's the gcc_mech.data */
+	if(!p->gcc_ctx == 0) {
+		dprintk("RPC: gss_ctx_free: called on p->gcc_ctx %p\n", p->gcc_ctx);
+		rpc_free(p->gcc_ctx);  
+    p->gcc_ctx = 0;
+	}
+	dprintk("RPC: gss_ctx_free: called on cacheent %p\n", p);
+	rpc_free(p);
+  p = 0;
+}
+
+static inline void
+gss_ctx_insert(struct gss_ctx_cacheent *p, struct gss_ctx_mapping *map)
+{
+	/* caller must hold writelock */
+	atomic_set(&p->gcc_refcount, 1);    /* refcount==1 indicates in use by the cache */
+	list_add(&p->gss_ctx_cache, &map->gss_ctx_cache);
+}
+
+void
+gss_clear_ctx_map(struct gss_ctx_mapping *map)
+{
+	struct list_head *l = NULL;
+	struct gss_ctx_cacheent *p = NULL;
+
+	l = &map->gss_ctx_cache;
+	while (!list_empty(l)) {
+		write_lock(&map->lock);
+		p = list_entry(l->next, struct gss_ctx_cacheent, gss_ctx_cache);
+		list_del(&p->gss_ctx_cache);
+	/* Since gss_ctx_put() can block, it can only be called safely if the
+	 * spinlock is not held. */
+		write_unlock(&map->lock);
+		gss_ctx_put(p);
+	}
+}
+
+
+
+/* Function: gss_searchbyctx()
+ *
+ * Description: search the map list for a given context.
+ *
+ * NOTE: input ctxid's point at gss_ctx_cacheents. 
+ */
+static inline struct gss_ctx_cacheent *
+gss_searchbyctx(struct gss_ctx_mapping *map, GSS_CTX_ID_T *ctxid)
+{
+	struct gss_ctx_cacheent *p,*cep = c_ctx(ctxid);
+	struct list_head *l;
+
+	/* caller must hold readlock */
+	list_for_each(l, &map->gss_ctx_cache) {
+		p = list_entry(l, struct gss_ctx_cacheent, gss_ctx_cache);
+                dprintk("gss_searchbyctx: p=%p  cep= %p\n",p,cep);
+		if (p == cep){
+			dprintk("gss_searchbyctx returning p: %p\n",p);
+			return p;
+		}
+	}
+	return NULL;
+}
+
+/* Function gss_create_cts_cacheent()
+ *
+ * Description; allocate a new gss_ctx_cacheent
+ */
+struct gss_ctx_cacheent *
+gss_create_cacheent(struct gss_ctx_mapping *map)
+{
+	struct gss_ctx_cacheent *p;
+
+	if(!map)
+		goto outerr;
+	if(!(p = gss_ctx_alloc())){
+		dprintk("RPC: gss_alloc: out of memory!\n");
+		goto outerr;
+	}
+
+out:
+	return p;
+outerr:
+	p = NULL;
+	goto out;
+}
+
+/* Function: gss_get_context()
+ *
+ * Description: Boolean wrapper for gssd_import_sec_context(). 
+ * A new gss_ctx_cacheent is created to store the security context 
+ * obtained from gssd.
+ * 
+ * Parameters:
+ *   INPUT
+ *   map: the context cache.
+ *   ctx: the GSS_CTX_ID_T returned from gssd_init_sec_context() or 
+ *        gssd_accept_sec_context(). this is a union context
+ *        that contains the mech OID as well as the internal ctx id
+ *   OUTPUT
+ *   ctx: pointer to the created gss_ctx_cacheent that contains the 
+ *        imported context.
+ *   min_stat: set by sub routines
+ *   maj_stat: return = 0 -> GSS_S_FAILURE
+ *             return = 1 -> GSS_S_COMPLETE
+ */
+
+
+u32
+gss_get_context(u32 *maj_stat, u32* min_stat,struct gss_ctx_mapping *map, GSS_CTX_ID_T *ctx)
+{
+	struct gss_ctx_cacheent *cep = NULL;
+	GSS_BUFFER_T	buf;
+
+	dprintk("RPC: gss_get_context: maj_stat %d," 
+          "min_stat %d, gss_ctx_mapping %p, ctx %p\n", 
+           *maj_stat, *min_stat, map, ctx);
+
+	if (gssd_import_sec_context(maj_stat,min_stat,ctx,&buf) < 0)
+		goto outerr;
+
+	dprintk("RPC: gss_get_context : buf %p:%d\n",buf.data,buf.len);
+
+	/* allocate cacheent */
+	if(!(cep = gss_create_cacheent(map))) {
+		*min_stat = -ENOMEM;	
+		goto outerr;
+	}
+
+	/* XXX internalize context: should switch on mechanism... */
+	if((k5_gss_import_sec_context(min_stat,&buf,&cep->gcc_ctx)) !=0)
+		goto outerr;
+
+	if((*min_stat = gss_get_ctx_mech(&cep->gcc_mech,ctx)) !=0)
+		goto outerr;	
+	cep->gcc_qop = GSS_C_QOP_DEFAULT;
+
+	if((*min_stat = gss_set_ctx(ctx,cep)))
+		goto outerr;	
+
+	/* insert cacheent into cache */
+  write_lock(&map->lock);
+	gss_ctx_insert(cep, map);
+  write_unlock(&map->lock);
+
+	print_krb5_gss_ctx_id_rec(k_ctx(ctx));
+	*maj_stat = GSS_S_COMPLETE;
+	return 1;
+outerr:
+	dprintk("RPC: gss_get_context: FAILED. err %d\n",*min_stat);
+	if(cep != NULL)
+		gss_ctx_free(cep);
+	*maj_stat = GSS_S_FAILURE;
+	return 0;
+}
+
+/* Funciton: gss_validate_context(GSS_CTX_ID_T *ctx_id)
+ *
+ * Description: lookup ctx_id in map. return boolean result
+ */
+u32
+gss_validate_context(GSS_CTX_ID_T *ctx_id,struct gss_ctx_mapping *map)
+{
+        struct gss_ctx_cacheent *p = NULL;
+
+        read_lock(&map->lock);
+        p = gss_searchbyctx(map,ctx_id);
+        read_unlock(&map->lock);
+        if(!p){
+                dprintk("gss_validate_context: context NOT found\n");
+                return 0;
+        }
+        else{
+                dprintk("gss_validate_context: found context: %p\n",p);
+                return 1;
+        }
+}
--- clean/net/sunrpc/gssd_clnt.c	Tue Feb 26 12:00:35 2002
+++ dirty/net/sunrpc/gssd_clnt.c	Mon Feb 25 12:08:45 2002
@@ -34,7 +34,7 @@
  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $Id: rpcsec_gss_nfsv4patch3.0.patch,v 1.2 2002/02/26 17:39:36 andros Exp $
+ * $Id: rpcsec_gss_nfsv4patch3.0.patch,v 1.2 2002/02/26 17:39:36 andros Exp $
  */
 
 #include <linux/config.h>
@@ -79,6 +79,7 @@
 /* NOTE: these structures mirror those declared in gssd's gss.x */
 struct gssd_init_sec_context_arg {
 	u32		uid;
+	u32   flags;
 	GSS_CTX_ID_T	ctx_id;
 	GSS_BUFFER_T	target_name;
 	GSS_OID		mech;
@@ -347,6 +348,7 @@
  */
 int
 gssd_init_sec_context(u32		uid,
+		      u32	       flags,
 		      u32	       *maj_statp,
 		      u32	       *min_statp,
 		      GSS_CTX_ID_T     *ctx_id,
@@ -367,6 +369,7 @@
 		return -EACCES;
 	}
 	arg.uid = uid;
+ 	arg.flags = flags;
 	arg.ctx_id = *ctx_id;
 	arg.target_name = *service_name;
 	arg.mech = *mech;
@@ -514,6 +517,8 @@
 
 	  dprintk("RPC: gssd_import_sec_context results: res.maj_stat %d res.min_stat %d res.ctx_token.len %d res.ctx_token.data %p\n",res.maj_stat, res.min_stat,res.ctx_token.len,res.ctx_token.data); 
 
+print_hexl((u_int *)res.ctx_token.data,8,0);
+
 		ctx_token.data = rpc_allocate(0, res.ctx_token.len);
 		memcpy(ctx_token.data, res.ctx_token.data,
 		       res.ctx_token.len);
@@ -583,13 +588,14 @@
 				struct gssd_init_sec_context_arg *argp)
 {
 	dprintk("RPC: xdr_encode_init_sec_context_arg"
-		"(uid %d, ctx %p:%d, name %p:%d, mech %p:%d, token %p:%d)\n",
-		argp->uid, argp->ctx_id.data, argp->ctx_id.len,
+		"(uid %d, flags %d,ctx %p:%d, name %p:%d, mech %p:%d, token %p:%d)\n",
+		argp->uid, argp->flags,argp->ctx_id.data, argp->ctx_id.len,
 		argp->target_name.data, argp->target_name.len,
 		argp->mech.data, argp->mech.len,
 		argp->input_token.data, argp->input_token.len);
 	
   	*p++ = (u32) htonl(argp->uid);
+		*p++ = (u32) htonl(argp->flags);
 	p = xdr_encode_netobj(p, &argp->ctx_id);
 	p = xdr_encode_netobj(p, &argp->target_name);
  	p = xdr_encode_netobj(p, &argp->mech);
--- clean/net/sunrpc/gss_generic_ordering.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_generic_ordering.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,214 @@
+/*
+ *  linux/net/sunrpc/gss_generic_ordering.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic/util_ordering.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * functions to check sequence numbers for replay and sequencing
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+#define QUEUE_LENGTH 20
+
+typedef struct _queue {
+   int do_replay;
+   int do_sequence;
+   int start;
+   int length;
+   unsigned int firstnum;
+   unsigned int elem[QUEUE_LENGTH];
+} queue;
+
+/* rep invariant:
+ *  - the queue is a circular queue.  The first element (q->elem[q->start])
+ * is the oldest.  The last element is the newest.
+ */
+
+#define QSIZE(q) (sizeof((q)->elem)/sizeof((q)->elem[0]))
+#define QELEM(q,i) ((q)->elem[(i)%QSIZE(q)])
+
+static void
+queue_insert(queue *q, int after, unsigned int seqnum)
+{
+   /* insert.  this is not the fastest way, but it's easy, and it's
+      optimized for insert at end, which is the common case */
+   int i;
+
+   /* common case: at end, after == q->start+q->length-1 */
+
+   /* move all the elements (after,last] up one slot */
+
+   for (i=q->start+q->length-1; i>after; i--)
+      QELEM(q,i+1) = QELEM(q,i);
+
+   /* fill in slot after+1 */
+
+   QELEM(q,after+1) = seqnum;
+
+   /* Either increase the length by one, or move the starting point up
+      one (deleting the first element, which got bashed above), as
+      appropriate. */
+
+   if (q->length == QSIZE(q)) {
+      q->start++;
+      if (q->start == QSIZE(q))
+	 q->start = 0;
+   } else {
+      q->length++;
+   }
+}
+   
+u32
+g_order_init(void **vqueue, u32 seqnum,
+	     int do_replay, int do_sequence)
+{
+   queue *q;
+
+   if ((q = (queue *) rpc_allocate(0,sizeof(queue))) == NULL)
+      return(ENOMEM);
+
+   q->do_replay = do_replay;
+   q->do_sequence = do_sequence;
+
+   q->start = 0;
+   q->length = 1;
+   q->firstnum = seqnum;
+   q->elem[q->start] = seqnum-1;
+
+   *vqueue = (void *) q;
+   return(0);
+}
+
+u32
+g_order_check(void **vqueue, u32 seqnum)
+{
+   queue *q;
+   int i;
+   
+   q = (queue *) (*vqueue);
+
+   if (!q->do_replay && !q->do_sequence)
+      return(GSS_S_COMPLETE);
+
+   /* rule 1: expected sequence number */
+
+   if (seqnum == QELEM(q,q->start+q->length-1)+1) { 
+      queue_insert(q, q->start+q->length-1, seqnum);
+      return(GSS_S_COMPLETE);
+   }
+
+   /* rule 2: > expected sequence number */
+
+   if ((seqnum > QELEM(q,q->start+q->length-1)+1) ||
+       (seqnum < q->firstnum)) {
+      queue_insert(q, q->start+q->length-1, seqnum);
+      if (q->do_replay && !q->do_sequence)
+	 return(GSS_S_COMPLETE);
+      else
+	 return(GSS_S_GAP_TOKEN);
+   }
+
+   /* rule 3: seqnum < seqnum(first) */
+
+   if ((seqnum < QELEM(q,q->start)) &&
+       (seqnum >= q->firstnum)) {
+      if (q->do_replay && !q->do_sequence)
+	 return(GSS_S_OLD_TOKEN);
+      else
+	 return(GSS_S_UNSEQ_TOKEN);
+   }
+
+   /* rule 4+5: seqnum in [seqnum(first),seqnum(last)]  */
+
+   else {
+      if (seqnum == QELEM(q,q->start+q->length-1))
+	 return(GSS_S_DUPLICATE_TOKEN);
+
+      for (i=q->start; i<q->start+q->length-1; i++) {
+	 if (seqnum == QELEM(q,i))
+	    return(GSS_S_DUPLICATE_TOKEN);
+	 if ((seqnum > QELEM(q,i)) && (seqnum < QELEM(q,i+1))) {
+	    queue_insert(q, i, seqnum);
+	    if (q->do_replay && !q->do_sequence)
+	       return(GSS_S_COMPLETE);
+	    else
+	       return(GSS_S_UNSEQ_TOKEN);
+	 }
+      }
+   }
+
+   /* this should never happen */
+   return(GSS_S_FAILURE);
+}
+
+void
+g_order_free(void **vqueue)
+{
+   queue *q;
+   
+   q = (queue *) (*vqueue);
+
+   rpc_free(q);
+
+   *vqueue = NULL;
+}
+
+/*
+ * These support functions are for the serialization routines
+ */
+u32
+g_queue_size(void *vqueue, size_t *sizep)
+{
+    *sizep += sizeof(queue);
+    return 0;
+}
+
+u32
+g_queue_internalize(void **vqueue, unsigned char **buf, size_t *lenremain)
+{
+    void *q;
+
+    if ((q = rpc_allocate(0,sizeof(queue))) == 0)
+  return ENOMEM;
+    memcpy(q, *buf, sizeof(queue));
+    *buf += sizeof(queue);
+    *lenremain -= sizeof(queue);
+    *vqueue = q;
+    return 0;
+}
--- clean/net/sunrpc/gss_generic_token.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_generic_token.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,241 @@
+/*
+ *  linux/net/sunrpc/gss_generic_token.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic/util_token.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+/* TWRITE_STR from gssapiP_generic.h */
+#define TWRITE_STR(ptr, str, len) \
+   memcpy((ptr), (char *) (str), (len)); \
+   (ptr) += (len);
+
+/* XXXX this code currently makes the assumption that a mech oid will
+   never be longer than 127 bytes.  This assumption is not inherent in
+   the interfaces, so the code can be fixed if the OSI namespace
+   balloons unexpectedly. */
+
+/* Each token looks like this:
+
+0x60				tag for APPLICATION 0, SEQUENCE
+					(constructed, definite-length)
+	<length>		possible multiple bytes, need to parse/generate
+	0x06			tag for OBJECT IDENTIFIER
+		<moid_length>	compile-time constant string (assume 1 byte)
+		<moid_bytes>	compile-time constant string
+	<inner_bytes>		the ANY containing the application token
+					bytes 0,1 are the token type
+					bytes 2,n are the token data
+
+For the purposes of this abstraction, the token "header" consists of
+the sequence tag and length octets, the mech OID DER encoding, and the
+first two inner bytes, which indicate the token type.  The token
+"body" consists of everything else.
+
+*/
+
+static int der_length_size(
+     int length)
+{
+   if (length < (1<<7))
+      return(1);
+   else if (length < (1<<8))
+      return(2);
+#if (SIZEOF_INT == 2)
+   else
+       return(3);
+#else
+   else if (length < (1<<16))
+      return(3);
+   else if (length < (1<<24))
+      return(4);
+   else
+      return(5);
+#endif
+}
+
+static void der_write_length(
+     unsigned char **buf,
+     int length)
+{
+   if (length < (1<<7)) {
+      *(*buf)++ = (unsigned char) length;
+   } else {
+      *(*buf)++ = (unsigned char) (der_length_size(length)+127);
+#if (SIZEOF_INT > 2)
+      if (length >= (1<<24))
+	 *(*buf)++ = (unsigned char) (length>>24);
+      if (length >= (1<<16))
+	 *(*buf)++ = (unsigned char) ((length>>16)&0xff);
+#endif
+      if (length >= (1<<8))
+	 *(*buf)++ = (unsigned char) ((length>>8)&0xff);
+      *(*buf)++ = (unsigned char) (length&0xff);
+   }
+}
+
+/* returns decoded length, or < 0 on failure.  Advances buf and
+   decrements bufsize */
+
+static int der_read_length(
+     unsigned char **buf,
+     int *bufsize)
+{
+   unsigned char sf;
+   int ret;
+
+   if (*bufsize < 1)
+      return(-1);
+   sf = *(*buf)++;
+   (*bufsize)--;
+   if (sf & 0x80) {
+      if ((sf &= 0x7f) > ((*bufsize)-1))
+	 return(-1);
+      if (sf > SIZEOF_INT)
+	  return (-1);
+      ret = 0;
+      for (; sf; sf--) {
+	 ret = (ret<<8) + (*(*buf)++);
+	 (*bufsize)--;
+      }
+   } else {
+      ret = sf;
+   }
+
+   return(ret);
+}
+
+/* returns the length of a token, given the mech oid and the body size */
+
+int g_token_size(
+     GSS_OID *mech,
+     unsigned int body_size)
+{
+   /* set body_size to sequence contents size */
+   body_size += 4 + (int) mech->len;         /* NEED overflow check */
+   return(1 + der_length_size(body_size) + body_size);
+}
+
+/* fills in a buffer with the token header.  The buffer is assumed to
+   be the right size.  buf is advanced past the token header */
+
+void g_make_token_header(
+     GSS_OID *mech,
+     int body_size,
+     unsigned char **buf,
+     int tok_type)
+{
+   *(*buf)++ = 0x60;
+   der_write_length(buf, 4 + mech->len + body_size);
+   *(*buf)++ = 0x06;
+   *(*buf)++ = (unsigned char) mech->len;
+   TWRITE_STR(*buf, mech->data, ((int) mech->len));
+   *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
+   *(*buf)++ = (unsigned char) (tok_type&0xff);
+}
+
+/*
+ * Given a buffer containing a token, reads and verifies the token,
+ * leaving buf advanced past the token header, and setting body_size
+ * to the number of remaining bytes.  Returns 0 on success,
+ * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
+ * mechanism in the token does not match the mech argument.  buf and
+ * *body_size are left unmodified on error.
+ */
+u32
+g_verify_token_header(
+     GSS_OID *mech,
+     int *body_size,
+     unsigned char **buf_in,
+     int tok_type,
+     int toksize)
+{
+   unsigned char *buf = *buf_in;
+   int seqsize;
+   GSS_OID toid;
+   int ret = 0;
+
+   if ((toksize-=1) < 0)
+      return(G_BAD_TOK_HEADER);
+   if (*buf++ != 0x60)
+      return(G_BAD_TOK_HEADER);
+
+   if ((seqsize = der_read_length(&buf, &toksize)) < 0)
+      return(G_BAD_TOK_HEADER);
+
+   if (seqsize != toksize)
+      return(G_BAD_TOK_HEADER);
+
+   if ((toksize-=1) < 0)
+      return(G_BAD_TOK_HEADER);
+   if (*buf++ != 0x06)
+      return(G_BAD_TOK_HEADER);
+ 
+   if ((toksize-=1) < 0)
+      return(G_BAD_TOK_HEADER);
+   toid.len = *buf++;
+
+   if ((toksize-=toid.len) < 0)
+      return(G_BAD_TOK_HEADER);
+   toid.data = buf;
+   buf+=toid.len;
+
+   if (! g_OID_equal(&toid, mech)) 
+      ret = G_WRONG_MECH;
+ 
+   /* G_WRONG_MECH is not returned immediately because it's more important
+      to return G_BAD_TOK_HEADER if the token header is in fact bad */
+
+   if ((toksize-=2) < 0)
+      return(G_BAD_TOK_HEADER);
+
+   if (ret)
+       return(ret);
+
+   if ((*buf++ != ((tok_type>>8)&0xff)) ||
+       (*buf++ != (tok_type&0xff))) 
+      return(G_WRONG_TOKID);
+
+   if (!ret) {
+	*buf_in = buf;
+	*body_size = toksize;
+   }
+
+   return(ret);
+}
--- clean/net/sunrpc/gss_intern_ctx.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_intern_ctx.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,119 @@
+/*
+ *  linux/net/sunrpc/gss_intern.c
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+u32
+k5_gss_import_sec_context(
+        u32    *min_status,
+        GSS_BUFFER_T   *inbuf,
+        krb5_pointer *ctx_handle) 
+{
+	krb5_gss_ctx_id_t ctx;
+	krb5_octet    *ibp;
+	u32 blen;
+	int length;
+	char *p;
+
+	dprintk("RPC: k5_gss_import_sec_context inbuf: %p:%d\n",
+	          inbuf->data,inbuf->len);
+
+/* strip away the gss mechglue union mechanism OID which will be
+ * used later to switch on the mechanism specific routine.
+ */
+	p = inbuf->data;
+	length = *p++;
+	length = (length << 8) + *p++;
+	length = (length << 8) + *p++;
+	length = (length << 8) + *p++;
+  /* check for ridiculous OID length */
+	if(length > inbuf->len) {
+		dprintk("RPC: k5_gss_import_sec_context union mech length too large %d:\n",
+		         length);
+		return(KG_BAD_LENGTH);
+	}
+	p += length;
+
+	ctx = (krb5_gss_ctx_id_t) NULL;
+	*min_status = 0;
+
+	ibp = (krb5_octet *)p;
+	blen = inbuf->len;
+	dprintk("k5_gss_import_sec_context\n");
+	if((*min_status = kg_ctx_internalize(0,
+                       (krb5_pointer *)&ctx, 
+                        &ibp, &blen))) {
+	dprintk("k5_gss_import_sec_context 1\n");
+		return(GSS_S_FAILURE);
+	}
+	dprintk("k5_gss_import_sec_context 2. ctx: %p\n",ctx);
+	*ctx_handle = (krb5_pointer)ctx;
+
+	dprintk("k5_gss_import_sec_context 3. ctx: %p\n",ctx);
+	return(0);
+}
+
+void
+print_krb5_gss_ctx_id_rec(krb5_gss_ctx_id_t k5_ctx)
+{
+	dprintk("some of krb5_gss_ctx_id_rec: \n");
+	if(!k5_ctx) return;
+	dprintk("     initiate:      %d\n",k5_ctx->initiate);
+	dprintk("     gss_flags:     0x%x\n",k5_ctx->gss_flags);
+	dprintk("     seed_init:     %d\n",k5_ctx->seed_init);
+	dprintk("     signalg:      %d\n",k5_ctx->signalg);
+	dprintk("     cksum_size:      %d\n",k5_ctx->cksum_size);
+	dprintk("     sealalg:      %d\n",k5_ctx->sealalg);
+	dprintk("     established:      %d\n",k5_ctx->established);
+	dprintk("   ENC types: \n");
+	if(k5_ctx->enc){
+	    dprintk("     enc->enctype:     %d\n",k5_ctx->enc->enctype);
+	    dprintk("     enc->length:     %d\n",k5_ctx->enc->length);
+	}else 
+	    dprintk("     NULL ENC\n");
+	if(k5_ctx->seq){
+	    dprintk("     seq->enctype:     %d\n",k5_ctx->seq->enctype);
+	    dprintk("     seq->length:     %d\n",k5_ctx->seq->length);
+	}else
+	    dprintk("     NULL SEQ\n");
+}
--- clean/net/sunrpc/gss_k5cksum.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5cksum.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,105 @@
+/*
+ *  linux/net/sunrpc/gss_k5cksum.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+extern const krb5_2_linux_digest digest_list[];
+
+krb5_error_code 
+krb5_c_make_checksum(
+	krb5_context context,
+	krb5_cksumtype cksumtype,
+	krb5_keyblock *key,
+	krb5_keyusage usage,
+	krb5_data *input,
+	krb5_checksum *cksum)
+{
+	int i;
+	krb5_data data;
+	krb5_error_code ret = 0;
+	size_t cksumlen;
+
+    /* the checksum length was just set in make_seal_token_v1
+    * so, either we remove that code, or remove this code....*/
+
+	if((i = find_digest(cksumtype)) == -1)
+		return(-EINVAL);
+
+	if (digest_list[i].keyhash)
+		(*(digest_list[i].keyhash->hash_size))(&cksumlen);
+	else if (digest_list[i].hash)
+		(*(digest_list[i].hash->hash_size))(&cksumlen);
+	else
+		return(-EINVAL);
+
+	cksum->length = cksumlen;
+
+	if ((cksum->contents = (krb5_octet *) rpc_allocate(0,cksum->length)) == NULL)
+		return(ENOMEM);
+
+	data.length = cksum->length;
+	data.data = cksum->contents;
+
+
+	dprintk("RPC:   krb5_c_make_checksum cksum->length %d input->length %d\n",
+	        cksum->length,input->length);
+
+	if (digest_list[i].keyhash) 
+		ret = (*(digest_list[i].keyhash->hash))(key, 0, input, &data);
+	else if (digest_list[i].hash)
+		ret = (*(digest_list[i].hash->hash))(1, input, &data);
+
+	if (!ret){
+		cksum->magic = KV5M_CHECKSUM;
+		cksum->checksum_type = cksumtype;
+	}
+	if (ret) {
+		memset(cksum->contents, 0, cksum->length);
+		rpc_free(cksum->contents);
+	}
+
+	dprintk("RPC: gss_k5cksum: returning %d\n",ret);
+	return(ret);
+}
--- clean/net/sunrpc/gss_k5decrypt.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5decrypt.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,123 @@
+/*
+ *  linux/net/sunrpc/gss_k5decrypt.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/crypto/raw/raw_decrypt.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/* combines functionality of kg_decrypt(), krb5_c_decrypt(), and 
+ * krb5_raw_decrypt()
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+#include <linux/crypto.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+extern const krb5_2_linux_keytypes cipher_list[];
+
+u32
+gss_k5decrypt(
+     krb5_keyblock *key,
+     int usage,
+     krb5_pointer iv,
+     krb5_pointer in,
+     krb5_pointer out,
+     int length)
+{
+    u32 code = 0;
+    int i = -1;
+    struct cipher_implementation *ci;
+    struct cipher_context *cx;
+    u32 local_iv[4] = {0,0,0,0};
+
+    dprintk("gss_k5decrypt:\n");
+    /* key->enctype was checked by the caller */
+
+    if (key->length != 8)
+        return(-EINVAL);            /*KRB5_BAD_KEYSIZE*/
+    if ((length%8) != 0)
+        return(-EINVAL);            /*KRB5_BAD_MSIZE*/
+
+
+    if((i = find_enctype(key->enctype)) == -1)
+        return( -EINVAL);
+
+    code = -ENOMEM;
+    ci = find_cipher_by_name(cipher_list[i].seal_name,1);
+
+    if (!ci)
+        goto out;
+    cx = (struct cipher_context *)rpc_allocate(0,sizeof(struct cipher_context));
+    if(!cx)
+        goto out;
+    cx->ci = ci;
+
+    cx->keyinfo = (u32 *)rpc_allocate(0,ci->key_schedule_size);
+    if(!cx->keyinfo)
+        goto clean1;
+
+    /*XXX need to check key parity here*/
+
+    switch (code = ci->set_key(cx, (char *)key->contents, key->length)) {
+    case -1: /*XXX need bad key error*/
+        code = -EINVAL;       /*KRB5DES_BAD_KEYPAR*/
+        goto clean2;
+    case -2: /*XXX need weak key error*/
+        code = -EINVAL;       /* KRB5DES_WEAK_KEY*/
+        goto clean2;
+    }
+
+    /* set initialization vector as per rfc1510 */
+    if (iv) {
+       memcpy(local_iv,iv, ci->ivsize);
+    } else {
+        memset(local_iv,0,ci->ivsize);
+    }
+
+    code = ci->decrypt(cx, (u8 *)in, (u8 *)out, ci->blocksize,local_iv);
+
+clean2:
+    rpc_free(cx->keyinfo);
+clean1:
+    rpc_free(cx);
+out:
+    return(code);
+}
--- clean/net/sunrpc/gss_k5encrypt.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5encrypt.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,154 @@
+/*
+ *  linux/net/sunrpc/gss_k5encrypt.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/crypto/raw/raw_encrypt.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* combines functionality of kg_encrypt(), krb5_c_encrypt(), and 
+ * krb5_raw_encrypt()
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+#include <linux/crypto.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+extern const krb5_2_linux_keytypes cipher_list[];
+
+u32
+gss_k5encrypt(
+	krb5_keyblock *key,
+	int usage,
+	krb5_pointer iv,
+	krb5_pointer in,
+	krb5_pointer out,
+	int length)
+{
+	u32 code = 0;
+	int i = -1;
+	struct cipher_implementation *ci;
+	struct cipher_context *cx;
+	u32 local_iv[8] = {0,0,0,0,0,0,0,0};
+
+	dprintk("gss_k5encrypt:\n");
+
+	dprintk("RPC: gss_k5encrypt: TOP out %p in %p in data:\n",out,in);
+	print_hexl((u32 *)in,length,0);
+
+	/* key->enctype was checked by the caller */
+
+	if (key->length != 8)
+		return(-EINVAL);            /*KRB5_BAD_KEYSIZE*/
+	if ((length%8) != 0)
+		return(-EINVAL);            /*KRB5_BAD_MSIZE*/
+
+
+	if((i = find_enctype(key->enctype)) == -1)
+		return( -EINVAL);
+
+	code = -ENOMEM;
+	dprintk("RPC: gss_k5encrypt calling find_cipher_by_name %s\n",
+	             cipher_list[i].seal_name);
+	ci = find_cipher_by_name(cipher_list[i].seal_name,1);
+
+	if (!ci)
+		goto out;
+	cx = (struct cipher_context *)rpc_allocate(0,sizeof(struct cipher_context));
+	if(!cx)
+		goto out;
+	cx->ci = ci;
+
+	dprintk("RPC: gss_k5encrypt ci->blocksize: %d\n",ci->blocksize);
+	cx->keyinfo = (u32 *)rpc_allocate(0,ci->key_schedule_size);
+	if(!cx->keyinfo)
+		goto clean1;
+
+    /*XXX need to check key parity here*/
+
+	dprintk("RPC: gss_k5encrypt : ci->setkey args: \n");
+	dprintk ("               key->contents %p, key->length %d\n",key->contents,key->length);
+
+	switch (code = ci->set_key(cx, (char *)key->contents, key->length)) {
+		case -1: /*XXX need bad key error*/
+			printk("RPC: gss_k5encrypt KRB5DES_BAD_KEYPAR\n");
+			code = -EINVAL;       /*KRB5DES_BAD_KEYPAR*/
+			goto clean2;
+		case -2: /*XXX need weak key error*/
+			printk("RPC: gss_k5encryptKRB5DES_WEAK_KEY\n");
+			code = -EINVAL;       /* KRB5DES_WEAK_KEY*/
+			goto clean2;
+	}
+
+	dprintk("RPC: gss_k5encrypt : iv %p: \n",iv);
+    /* set initialization vector as per rfc1510 
+		* local_iv is set to zero unless input iv is set..*/
+	if (iv) {
+		memcpy(local_iv,iv, ci->ivsize);
+	} 
+	/* need to use length parameter to do for loop for lengths 
+	* greater than 8...
+	*/
+
+#if 0
+	dprintk("RPC: gss_k5encrypt : calling ci->encrypt:\n");
+	dprintk("     in:%p  in data:\n",in);
+	print_hexl(in,length,0);
+	dprintk("     out %p\n",out);
+	dprintk("     ci->blocksize %d\n",ci->blocksize);
+	dprintk("     local_iv %p local_iv data:\n",local_iv);
+	print_hexl((u32 *)local_iv,8,0);
+#endif
+
+	code = ci->encrypt(cx, (u8 *)in, (u8 *)out,length,local_iv);
+
+#if 0
+	dprintk("RPC: gss_k5encrypt : after ci->encrypt:\n");
+	dprintk("     out:%p  out data:\n",out);
+	dprint_hexl(out,16,0);
+#endif
+
+clean2:
+	rpc_free(cx->keyinfo);
+clean1:
+	rpc_free(cx);
+out:
+	dprintk("gss_k5encrypt returns %d\n",code);
+	return(code);
+}
--- clean/net/sunrpc/gss_k5hash_md5.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5hash_md5.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,123 @@
+/*
+ *  linux/net/sunrpc/gss_k5hash_md5.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/crypto/hash_provider/hash_md5.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ * 
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+#include <linux/crypto.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+static void
+gss_k5_md5_hash_size(size_t *output)
+{
+    *output = RSA_MD5_CKSUM_LENGTH;
+}
+
+static void
+gss_k5_md5_block_size(size_t *output)
+{
+	*output = 64;
+}
+
+static krb5_error_code
+gss_k5_md5_hash(
+	unsigned int icount, 
+	krb5_data *input,
+	krb5_data *output)
+{
+	int i,ret=0;
+	struct digest_context *dx;
+	struct digest_implementation *di;
+	u8* digest_out;
+
+	dprintk("RPC: gss_k5_md5_hash\n");
+	if (output->length != RSA_MD5_CKSUM_LENGTH)
+		return(-EINVAL);
+
+    /* initialize the kernel hash interface */
+	ret = -ENOMEM;
+	di = find_digest_by_name("md5",1);
+	if (!di)
+		goto out;
+	dx = (struct digest_context *)rpc_allocate(0,sizeof(struct digest_context));
+	if(!dx)
+		goto out;
+
+	dx->di = di;
+	dx->digest_info = (u32 *)rpc_allocate(0,di->working_size);
+	if(!dx->digest_info)
+		goto clean1;
+	digest_out = (unsigned char *) rpc_allocate (0,di->blocksize);
+	if (!digest_out)
+		goto clean2;
+	di->open(dx);
+
+	for (i=0; i<icount; i++){
+		dprintk("gss_k5_md5_hash: INPUT TEXT: u8 len %d\n",input[i].length); 
+		print_hexl((u32 *)input[i].data, input[i].length,0);
+		di->update(dx,input[i].data, input[i].length);
+	}
+	di->close(dx,digest_out);
+
+	memcpy(output->data, digest_out, RSA_MD5_CKSUM_LENGTH);
+#if 0
+	dprintk("gss_k5_md5_hash: digest buffer HASH RESULT byte len %d\n", 
+	         RSA_MD5_CKSUM_LENGTH);
+	print_hexl((u32 *)digest_out,RSA_MD5_CKSUM_LENGTH,0);
+	dprintk("gss_k5_md5_hash: output buffer HASH RESULT byte len %d\n", RSA_MD5_CKSUM_LENGTH);
+	print_hexl((u32 *)output->data,RSA_MD5_CKSUM_LENGTH,0);
+#endif /*0*/
+	ret = 0;
+	rpc_free(digest_out);
+clean2:
+	rpc_free(dx->digest_info);
+clean1:
+	rpc_free(dx);
+out:
+	return(ret);
+}
+
+const struct krb5_hash_provider krb5_hash_md5 = {
+	gss_k5_md5_hash_size,
+	gss_k5_md5_block_size,
+	gss_k5_md5_hash
+};
--- clean/net/sunrpc/gss_k5seal.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5seal.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,442 @@
+/*
+ *  linux/net/sunrpc/gss_k5seal.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+
+static krb5_error_code
+make_seal_token_v1(
+	krb5_context context,
+	krb5_keyblock *enc,
+	krb5_keyblock *seq,
+	krb5_int32 *seqnum,
+	int direction,
+	GSS_BUFFER_T *text,
+	GSS_BUFFER_T *token,
+	int signalg,
+	int cksum_size,
+	int sealalg,
+	int encrypt,
+	int toktype,
+	int bigend,
+	GSS_OID *oid)
+{
+	krb5_error_code code=0;
+	size_t sumlen;
+	char *data_ptr;
+	krb5_data plaind;
+	krb5_checksum md5cksum;
+	krb5_checksum cksum;
+	int conflen=0, tmsglen, tlen;
+	unsigned char *t, *ptr;
+	int encblksize, sumblksize;
+
+    /* will eventually add support for other algorithms */
+	dprintk("RPC: gss_k5seal: signalg %d\n",signalg);
+	switch (signalg) {
+		case SGN_ALG_DES_MAC_MD5:
+			dprintk("RPC: gss_k5seal: signalg SGN_ALG_DES_MAC_MD5 %d\n",
+			        SGN_ALG_DES_MAC_MD5);
+			sumblksize = 1;
+		break;
+		default:
+			dprintk("RPC: gss_k5seal: SIGN: RETURNING KG_BAD_SIGN_TYPE \n");
+			return KG_BAD_SIGN_TYPE;
+	}
+	dprintk("RPC: gss_k5seal: sealalg %d\n",sealalg);
+	switch (sealalg) {
+		case SEAL_ALG_NONE:
+		case SEAL_ALG_DES:
+			dprintk("RPC: gss_k5seal: signalg SEAL_ALG_NONE/DES %d\n",sealalg);
+			encblksize = 8;
+		break;
+		default:
+			dprintk("RPC: gss_k5seal: SEAL: RETURNING KG_BAD_SIGN_TYPE \n");
+			return KG_BAD_SIGN_TYPE;
+	}
+
+    /* create the token buffer */
+
+	if (toktype == KG_TOK_SEAL_MSG) {
+		if (bigend && !encrypt) {
+			tmsglen = text->len;
+		} else {
+			code = k5_get_blocksize(enc->enctype,&conflen);
+			if(code)
+				return code;
+			/* XXX knows that des block size is 8 */
+			tmsglen = (conflen+text->len+8)&(~7);
+			dprintk("RPC:make_seal_token_v1: tmsglen: %d \n",tmsglen);
+		}
+	} else {
+		tmsglen = 0;
+	}
+
+	tlen = g_token_size((GSS_OID *) oid, 14+cksum_size+tmsglen);
+
+	if ((t = (unsigned char *) rpc_allocate(0,tlen)) == NULL)
+		return(ENOMEM);
+
+	/*** fill in the token */
+
+	ptr = t;
+
+	g_make_token_header((GSS_OID *) oid, 14+cksum_size+tmsglen, &ptr, toktype);
+
+	/* 0..1 SIGN_ALG */
+
+	ptr[0] = signalg & 0xff;
+	ptr[1] = (signalg >> 8) & 0xff;
+
+	/* 2..3 SEAL_ALG or Filler */
+
+	if ((toktype == KG_TOK_SEAL_MSG) && encrypt) {
+		ptr[2] = sealalg & 0xff;
+		ptr[3] = (sealalg >> 8) & 0xff;
+	} else {
+		/* No seal */
+		ptr[2] = 0xff;
+		ptr[3] = 0xff;
+	}
+
+	ptr[4] = 0xff;
+	ptr[5] = 0xff;
+
+	/* pad the plaintext, encrypt if needed, and stick it in the token */
+
+	/* initialize the the cksum */
+	switch (signalg) {
+		case SGN_ALG_DES_MAC_MD5:
+			md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+		break;
+		default:
+			return KG_BAD_SIGN_TYPE;
+	}
+
+	if ((code = k5_get_checksum_length(md5cksum.checksum_type, &sumlen)))
+		return(code);
+	md5cksum.length = sumlen;
+
+	if (toktype == KG_TOK_SEAL_MSG) {
+#if 0 /* not supported yet*/
+	unsigned char *plain;
+	unsigned char pad;
+
+		if (!bigend || encrypt) {
+			if ((plain = (unsigned char *) rpc_allocate(0,tmsglen)) == NULL) {
+				rpc_free(t);
+				return(ENOMEM);
+			}
+			if ((code = kg_make_confounder(context, enc, plain))) {
+				rpc_free(plain);
+				rpc_free(t);
+				return(code);
+			}
+			memcpy(plain+conflen, text->data, text->len);
+
+			/* XXX 8 is DES cblock size */
+			pad = 8-(text->len%8);
+
+	    memset(plain+conflen+text->len, pad, pad);
+		} else {
+			/* plain is never used in the bigend && !encrypt case */
+			plain = NULL;
+		}
+
+		if (encrypt) {
+			if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
+			        (krb5_pointer) plain,
+			        (krb5_pointer) (ptr+cksum_size+14), tmsglen))) {
+				if (plain)
+					rpc_free(plain);
+				rpc_free(t);
+				return(code);
+			}
+		} else {
+			if (bigend)
+				memcpy(ptr+14+cksum_size, text->data, text->len);
+			else
+				memcpy(ptr+14+cksum_size, plain, tmsglen);
+		}
+
+		/* compute the checksum */
+
+		/* 8 = head of token body as specified by mech spec */
+		if (! (data_ptr =
+		     (char *) rpc_allocate(0,8 + (bigend ? text->len : tmsglen)))) {
+			if (plain)
+				rpc_free(plain);
+			rpc_free(t);
+			return(ENOMEM);
+		}
+		(void) memcpy(data_ptr, ptr-2, 8);
+		if (bigend)
+			(void) memcpy(data_ptr+8, text->data, text->len);
+		else
+			(void) memcpy(data_ptr+8, plain, tmsglen);
+		plaind.length = 8 + (bigend ? text->len : tmsglen);
+		plaind.data = data_ptr;
+		code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
+				    KG_USAGE_SIGN, &plaind, &md5cksum);
+		rpc_free(data_ptr);
+
+		if (code) {
+			if (plain)
+				rpc_free(plain);
+			rpc_free(t);
+			return(code);
+		}
+
+		if (plain)
+			rpc_free(plain);
+#endif /*0*/
+		/* not supported yet*/
+	return -EINVAL;
+	} else {
+	/* Sign only.  */
+	/* compute the checksum */
+
+		if (! (data_ptr = (char *) rpc_allocate(0,8 + text->len))) {
+			rpc_free(t);
+			return(ENOMEM);
+		}
+		(void) memcpy(data_ptr, ptr-2, 8);
+		(void) memcpy(data_ptr+8, text->data, text->len);
+		plaind.length = 8 + text->len;
+		plaind.data = data_ptr;
+		code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
+				    KG_USAGE_SIGN, &plaind, &md5cksum);
+		rpc_free(data_ptr);
+		if (code) {
+			rpc_free(t);
+			return(code);
+		}
+	}
+
+	switch(signalg) {
+		case SGN_ALG_DES_MAC_MD5:
+		case 3:
+			dprintk("RPC: make_seal_token:SGN_ALG_DES_MAC_MD5: calling gss_k5encrypt CBC MAC\n");
+			/* this code uses the oid to determine if the ivec for des-cbc should
+			* be NULL, or to use the contentes of the krb5_key. i believe this
+			* assumes that the default oid (0x0) is used. since i have spkm3 and 
+			* lipkey coming down the line, i use the official krb5 oid, which
+			* breaks this code.
+		 	* XXX rfc1964 notes that all gss verifiers using the DES MAC MD% 
+			* checksum always use a NULL ivec, so hard code it for now.
+			* this may be changed when data integrity cksum is enabled.
+			if ((code = gss_k5encrypt(seq, KG_USAGE_SEAL,
+			              (g_OID_equal(oid, &gss_mech_krb5_oid) ?
+			              seq->contents : NULL),
+			              md5cksum.contents, md5cksum.contents, 16))) {
+			*
+			*/
+			if ((code = gss_k5encrypt(seq, KG_USAGE_SEAL,
+				                 NULL,
+				                 md5cksum.contents, 
+				                 md5cksum.contents, 16))) {
+				dprintk("make_seal_token: gss_k5encrypt FAILED returns code %d\n",code);
+				rpc_free(md5cksum.contents);
+				rpc_free(t);
+				return code;
+			}
+			dprintk("RPC: make_seal_token: gss_k5encrypt returns %d OUTPUT:\n",
+			       code);
+			print_hexl((u32 *)md5cksum.contents,16,0);
+
+			cksum.length = cksum_size;
+			cksum.contents = md5cksum.contents + 16 - cksum.length;
+			memcpy(ptr+14, cksum.contents, cksum.length);
+
+			dprintk("make_seal_token: ptr with cksum data: \n");
+			print_hexl((u32*)ptr, 14+8, 0);
+		break;
+		default:
+      return KG_BAD_SIGN_TYPE;
+	}
+
+	rpc_free(md5cksum.contents);
+
+	/* create the seq_num */
+
+	dprintk("RPC: make_seal_token: calling kg_make_seq_num\n");
+	if ((code = kg_make_seq_num(seq, direction?0:0xff, *seqnum,
+	             ptr+14, ptr+6))) {
+		rpc_free(t);
+		return(code);
+	}
+	dprintk("RPC: make_seal_token: kg_make_seq_num returns %d\n",code);
+
+	/* that's it.  return the token */
+	(*seqnum)++;
+	token->len = tlen;
+	token->data = (void *) t;
+
+#if 0
+	dprintk("RPC: kg_seal: DONE! token:\n");
+	print_hexl((u32 *)token->data,token->len,0);
+#endif /*0*/
+
+	return(0);
+}
+
+/* if signonly is true, ignore conf_req, conf_state,
+   and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
+
+/* NOTE: caller validates the context_handle*/
+u32
+kg_seal(
+	krb5_context context,
+	u32 *minor_status,
+	GSS_CTX_ID_T *context_handle,
+	int conf_req_flag,
+	int qop_req,
+	GSS_BUFFER_T *input_message_buffer,
+	int *conf_state,
+	GSS_BUFFER_T *output_message_buffer,
+	int toktype)
+{
+	krb5_gss_ctx_id_rec *ctx;
+	krb5_error_code code;
+	krb5_timestamp now;
+
+	output_message_buffer->len = 0;
+	output_message_buffer->data = NULL;
+
+	/* only default qop or matching established cryptosystem is allowed */
+#if 0
+	switch (qop_req & GSS_KRB5_CONF_C_QOP_MASK) {
+		case GSS_C_QOP_DEFAULT:
+		break;
+		default:
+			unknown_qop:
+			*minor_status = (u32) G_UNKNOWN_QOP;
+			return GSS_S_FAILURE;
+			case GSS_KRB5_CONF_C_QOP_DES:
+			if (ctx->sealalg != SEAL_ALG_DES) {
+				bad_qop:
+				*minor_status = (u32) G_BAD_QOP;
+				return GSS_S_FAILURE;
+			}
+		break;
+		case GSS_KRB5_CONF_C_QOP_DES3:
+			if (ctx->sealalg != SEAL_ALG_DES3)
+				goto bad_qop;
+		break;
+		}
+
+	switch (qop_req & GSS_KRB5_INTEG_C_QOP_MASK) {
+		case GSS_C_QOP_DEFAULT:
+		break;
+		default:
+			goto unknown_qop;
+		case GSS_KRB5_INTEG_C_QOP_MD5:
+		case GSS_KRB5_INTEG_C_QOP_DES_MD5:
+		case GSS_KRB5_INTEG_C_QOP_DES_MAC:
+			if (ctx->sealalg != SEAL_ALG_DES)
+				goto bad_qop;
+		break;
+		case GSS_KRB5_INTEG_C_QOP_HMAC_SHA1:
+			if (ctx->sealalg != SEAL_ALG_DES3KD)
+				goto bad_qop;
+		break;
+	}
+#else
+	if (qop_req != 0) {
+		*minor_status = (u32) G_UNKNOWN_QOP;
+		return GSS_S_FAILURE;
+	}
+#endif
+
+
+	ctx = k_ctx(context_handle);
+
+	if (! ctx->established) {
+		*minor_status = KG_CTX_INCOMPLETE;
+		return(GSS_S_NO_CONTEXT);
+	}
+
+	now = jiffies;
+
+	code = make_seal_token_v1(context, ctx->enc, ctx->seq,
+			      &ctx->seq_send, ctx->initiate,
+			      input_message_buffer, output_message_buffer,
+			      ctx->signalg, ctx->cksum_size, ctx->sealalg,
+			      conf_req_flag, toktype, ctx->big_endian,
+			      ctx->mech_used);
+
+	if (code) {
+		*minor_status = code;
+		return(GSS_S_FAILURE);
+	}
+
+	if (conf_state)
+		*conf_state = conf_req_flag;
+
+	*minor_status = 0;
+	return((ctx->endtime < now)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE);
+}
--- clean/net/sunrpc/gss_k5ser.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5ser.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,1040 @@
+/*
+ *  linux/net/sunrpc/gss_k5ser.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/krb5/krb/ser_*.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+
+/*
+ * Copyright 1995 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 <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+
+/*
+ * This module contains routines to [de]serialize 
+ *	krb5_gss_enc_desc and krb5_gss_ctx_id_t.
+ *
+ * it's called to import the krb5 gss context into the kernel 
+ * which only needs the pieces of the context necessary for encryption,
+ * decryption, and gss seq numbering. 
+ *
+ * NOTE:  the _NOT_USED_YET_ flag is used to exclude pieces of the code
+ * that we are not yet using...
+ *
+ * here are the pieces of struct gss_krb5_gss_ctx_id_rec that are needed:
+ *    int initiate;
+ *    int seed_init;
+ *    unsigned char seed[16];
+ *    krb5_keyblock *subkey;
+ *    int sealalg;
+ *    krb5_keyblock *enc;
+ *    krb5_keyblock *seq;
+ *    krb5_timestamp endtime;
+ *    void *seqstate;
+ *    int established;
+ *    int big_endian;
+ *    GSS_OID *mech_used;
+ */
+
+/*
+ * Internalize this krb5_gss_ctx_id_t.
+ *
+ * NOTE: due to the _NOT_USED_YET_ excluded code, upon return, 
+ * the buffer and lenremain are not set correctly...
+ */
+krb5_error_code
+kg_ctx_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_gss_ctx_id_rec	*ctx;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+		dprintk("RPC: kg_ctx_internalize: argp %p *buffer %p \n",argp,*buffer);
+		print_hexl((u32 *)*buffer,8,0);
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KG_CONTEXT) {
+	kret = ENOMEM;
+
+	/* Get a context */
+	if ((remain >= ((10*sizeof(krb5_int32))+sizeof(ctx->seed))) &&
+	    (ctx = (krb5_gss_ctx_id_rec *)
+	     rpc_allocate(0,sizeof(krb5_gss_ctx_id_rec)))) {
+	    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
+
+	    /* Get static data */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->initiate = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->gss_flags = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->seed_init = (int) ibuf;
+	    (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed,
+					 sizeof(ctx->seed),
+					 &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->signalg = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->cksum_size = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->sealalg = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->endtime = (krb5_timestamp) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->krb_flags = (krb5_flags) ibuf;
+	    (void) krb5_ser_unpack_int32(&ctx->seq_send, &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&ctx->seq_recv, &bp, &remain);
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->established = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->big_endian = (int) ibuf;
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    ctx->nctypes = (int) ibuf;
+
+	    if ((kret = kg_oid_internalize(kcontext, (void *)&ctx->mech_used, &bp,
+					   &remain))) {
+		 if (kret == EINVAL)
+		      kret = 0;
+	    }
+	    /* Now get substructure data */
+#ifdef _NOT_USED_YET_
+	    if ((kret = krb5_internalize_opaque(kcontext,
+						KV5M_PRINCIPAL,
+						(krb5_pointer *) &ctx->here,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_internalize_opaque(kcontext,
+						KV5M_PRINCIPAL,
+						(krb5_pointer *) &ctx->there,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+#else /*_NOT_USED_YET_*/
+	    /* skip principal name data */
+		kret = krb5_principal_skip(&bp, &remain);
+		if(kret == EINVAL) kret=0;
+		kret = krb5_principal_skip(&bp, &remain);
+		if(kret == EINVAL) kret=0;
+#endif /*_NOT_USED_YET_*/
+	    if (!kret &&
+		(kret = krb5_keyblock_internalize(kcontext,
+						(krb5_pointer *) &ctx->subkey,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_keyblock_internalize(kcontext,
+						(krb5_pointer *) &ctx->enc,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+	    if (!kret &&
+		(kret = krb5_keyblock_internalize(kcontext,
+						(krb5_pointer *) &ctx->seq,
+						&bp, &remain))) {
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+
+	    if (!kret) {
+		kret = kg_queue_internalize(kcontext, &ctx->seqstate,
+					    &bp, &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+		
+#ifdef _NOT_USED_YET_ 
+/* XXX : stop here, don't need the rest of the context to perfrom 
+ * encryption/decryption.
+ */
+	    if (!kret)
+		kret = krb5_internalize_opaque(kcontext,
+					       KV5M_AUTH_CONTEXT,
+				       (krb5_pointer *) &ctx->auth_context,
+					       &bp, &remain);
+		
+	    if (!kret) {
+		if (ctx->nctypes) {
+		    if ((ctx->ctypes = (krb5_cksumtype *)
+			 rpc_allocate(0,ctx->nctypes*sizeof(krb5_cksumtype))) == NULL){
+			kret = ENOMEM;
+		    }
+
+		    for (i=0; i<ctx->nctypes; i++) {
+			if (!kret) {
+			    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+			    ctx->ctypes[i] = (krb5_cksumtype) ibuf;
+			}
+		    }
+		}
+	    }
+
+	    /* Get trailer */
+	    if (!kret &&
+		!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) &&
+		(ibuf == KG_CONTEXT)) {
+		*buffer = bp;
+		*lenremain = remain;
+		*argp = (krb5_pointer) ctx;
+	    }
+	    else {
+		if (!kret && (ibuf != KG_CONTEXT))
+		    kret = EINVAL;
+		if (ctx->seq)
+		    krb5_free_keyblock(kcontext, ctx->seq);
+		if (ctx->enc)
+		    krb5_free_keyblock(kcontext, ctx->enc);
+		if (ctx->subkey)
+		    krb5_free_keyblock(kcontext, ctx->subkey);
+		if (ctx->there)
+		    krb5_free_principal(kcontext, ctx->there);
+		if (ctx->here)
+		    krb5_free_principal(kcontext, ctx->here);
+		rpc_free(ctx);
+	    }
+#else /*_NOT_USED_YET_*/
+			if(!kret){
+				*buffer = bp;
+				*lenremain = remain;
+				*argp = (krb5_pointer) ctx;
+			}else{
+				if (ctx->seq)
+					krb5_free_keyblock(kcontext, ctx->seq);
+				if (ctx->enc)
+					krb5_free_keyblock(kcontext, ctx->enc);
+				if (ctx->subkey)
+					krb5_free_keyblock(kcontext, ctx->subkey);
+				rpc_free(ctx);
+			}
+#endif /*_NOT_USED_YET_*/
+		}
+	}
+
+    return(kret);
+}
+
+krb5_error_code
+kg_oid_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+     krb5_error_code	kret;
+     GSS_OID *oid;
+     krb5_int32 ibuf;
+     krb5_octet		*bp;
+     size_t		remain;
+
+     bp = *buffer;
+     remain = *lenremain;
+
+     /* Read in and check our magic number */
+     if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	return (EINVAL);
+
+     if (ibuf != KV5M_GSS_OID)
+	 return (EINVAL);
+
+     oid = (GSS_OID *) rpc_allocate(0,sizeof(GSS_OID));
+     if (oid == NULL)
+	  return ENOMEM;
+     (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+     oid->len = ibuf;
+     oid->data = rpc_allocate(0,ibuf);
+     if (oid->data == 0) {
+	     rpc_free(oid);
+	     return ENOMEM;
+     }
+     (void) krb5_ser_unpack_bytes((krb5_octet *) oid->data,
+				  oid->len, &bp, &remain);
+     
+     /* Read in and check our trailing magic number */
+     if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	return (EINVAL);
+
+     if (ibuf != KV5M_GSS_OID)
+	 return (EINVAL);
+
+     *buffer = bp;
+     *lenremain = remain;
+     *argp = (krb5_pointer) oid;
+     return 0;
+}
+
+krb5_error_code
+kg_queue_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+     krb5_error_code	kret;
+     krb5_int32 ibuf;
+     krb5_octet		*bp;
+     size_t		remain;
+/*
+     GSS_OID *oid;
+*/
+
+     bp = *buffer;
+     remain = *lenremain;
+
+     /* Read in and check our magic number */
+     if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	return (EINVAL);
+
+     if (ibuf != KV5M_GSS_QUEUE)
+	 return (EINVAL);
+
+     g_queue_internalize(argp, &bp, &remain);
+
+     /* Read in and check our trailing magic number */
+     if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+	return (EINVAL);
+
+     if (ibuf != KV5M_GSS_QUEUE)
+	 return (EINVAL);
+
+     *buffer = bp;
+     *lenremain = remain;
+     return 0;
+}
+
+
+/*
+ * krb5_keyblock_internalize()	- Internalize the krb5_keyblock.
+ */
+krb5_error_code
+krb5_keyblock_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_keyblock	*keyblock;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_KEYBLOCK) {
+	kret = ENOMEM;
+
+	/* Get a keyblock */
+	if ((remain >= (3*sizeof(krb5_int32))) &&
+	    (keyblock = (krb5_keyblock *) rpc_allocate(0,sizeof(krb5_keyblock)))) {
+	    memset(keyblock, 0, sizeof(krb5_keyblock));
+
+	    /* Get the enctype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    keyblock->enctype = (krb5_enctype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    keyblock->length = (int) ibuf;
+
+	    /* Get the string */
+	    if ((keyblock->contents = (krb5_octet *) rpc_allocate(0,(size_t) (ibuf)))&&
+		!(kret = krb5_ser_unpack_bytes(keyblock->contents,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		if (!kret && (ibuf == KV5M_KEYBLOCK)) {
+		    kret = 0;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    keyblock->magic = KV5M_KEYBLOCK;
+		    *argp = (krb5_pointer) keyblock;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (keyblock->contents)
+		    rpc_free(keyblock->contents);
+		rpc_free(keyblock);
+	    }
+	}
+    }
+    return(kret);
+}
+
+void
+krb5_free_keyblock(
+     krb5_context context,
+     register krb5_keyblock *key)
+{
+	if (key->contents) {
+		memset(key->contents, 0, key->length);
+		rpc_free(key->contents);
+		key->contents = 0;
+	}
+	rpc_free(key);
+}
+
+/*
+ * krb5_principal_skip()	- skip the krb5_principal.
+ */
+krb5_error_code
+krb5_principal_skip(
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+	bp = *buffer;
+	remain = *lenremain;
+	kret = EINVAL;
+	/* Read our magic number */
+	if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+		ibuf = 0;
+	if (ibuf == KV5M_PRINCIPAL) {
+		if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
+			/* skip the string */
+			bp += ibuf;
+			remain -=ibuf;
+			kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+			if (!kret && (ibuf == KV5M_PRINCIPAL)) {
+				*buffer = bp;
+				*lenremain = remain;
+			}
+		}
+	}
+return(kret);
+}
+
+#if _NOT_USED_YET_
+/*
+ * krb5_principal_internalize()	- Internalize the krb5_principal.
+ */
+krb5_error_code
+krb5_principal_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_principal	principal;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    char		*tmpname;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+			ibuf = 0;
+    if (ibuf == KV5M_PRINCIPAL) {
+			kret = ENOMEM;
+
+	/* See if we have enough data for the length */
+	if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
+	    /* Get the string */
+	    if ((tmpname = (char *) rpc_allocate(0,(size_t) (ibuf+1))) &&
+		!(kret = krb5_ser_unpack_bytes((krb5_octet *) tmpname,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		tmpname[ibuf] = '\0';
+
+		/* Parse the name to a principal structure */
+		principal = (krb5_principal) NULL;
+		kret = krb5_parse_name(kcontext, tmpname, &principal);
+		if (!kret) {
+		    kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		    if (!kret && (ibuf == KV5M_PRINCIPAL)) {
+			*buffer = bp;
+			*lenremain = remain;
+			*argp = principal;
+		    }
+		    else
+			kret = EINVAL;
+		}
+		if (kret && principal)
+		    krb5_free_principal(kcontext, principal);
+		rpc_free(tmpname);
+	    }
+	}
+    }
+    return(kret);
+}
+/*
+ * krb5_checksum_internalize()	- Internalize the krb5_checksum.
+ */
+static krb5_error_code
+krb5_checksum_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_checksum	*checksum;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_CHECKSUM) {
+	kret = ENOMEM;
+
+	/* Get a checksum */
+	if ((remain >= (2*sizeof(krb5_int32))) &&
+	    (checksum = (krb5_checksum *) rpc_allocate(0,sizeof(krb5_checksum)))) {
+	    memset(checksum, 0, sizeof(krb5_checksum));
+
+	    /* Get the checksum_type */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    checksum->checksum_type = (krb5_cksumtype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    checksum->length = (int) ibuf;
+
+	    /* Get the string */
+	    if (!ibuf ||
+		((checksum->contents = (krb5_octet *)
+		  rpc_allocate(0,(size_t) (ibuf))) &&
+		 !(kret = krb5_ser_unpack_bytes(checksum->contents,
+						(size_t) ibuf,
+						&bp, &remain)))) {
+
+		/* Get the trailer */
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		if (!kret && (ibuf == KV5M_CHECKSUM)) {
+		    checksum->magic = KV5M_CHECKSUM;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) checksum;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (checksum->contents)
+		    rpc_free(checksum->contents);
+		rpc_free(checksum);
+	    }
+	}
+    }
+    return(kret);
+}
+/*
+ * krb5_address_internalize()	- Internalize the krb5_address.
+ */
+krb5_error_code
+krb5_address_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_address	*address;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_ADDRESS) {
+	kret = ENOMEM;
+
+	/* Get a address */
+	if ((remain >= (2*sizeof(krb5_int32))) &&
+	    (address = (krb5_address *) rpc_allocate(0,sizeof(krb5_address)))) {
+	    memset(address, 0, sizeof(krb5_address));
+
+	    address->magic = KV5M_ADDRESS;
+
+	    /* Get the addrtype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    address->addrtype = (krb5_addrtype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    address->length = (int) ibuf;
+
+	    /* Get the string */
+	    if ((address->contents = (krb5_octet *) rpc_allocate(0,(size_t) (ibuf))) &&
+		!(kret = krb5_ser_unpack_bytes(address->contents,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		/* Get the trailer */
+		if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+		    ibuf = 0;
+
+		if (!kret && (ibuf == KV5M_ADDRESS)) {
+		    address->magic = KV5M_ADDRESS;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) address;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (address->contents)
+		    rpc_free(address->contents);
+		rpc_free(address);
+	    }
+	}
+    }
+    return(kret);
+}
+/*
+ * krb5_authdata_internalize()	- Internalize the krb5_authdata.
+ */
+static krb5_error_code
+krb5_authdata_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_authdata	*authdata;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_AUTHDATA) {
+	kret = ENOMEM;
+
+	/* Get a authdata */
+	if ((remain >= (2*sizeof(krb5_int32))) &&
+	    (authdata = (krb5_authdata *) rpc_allocate(0,sizeof(krb5_authdata)))) {
+	    memset(authdata, 0, sizeof(krb5_authdata));
+
+	    /* Get the ad_type */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authdata->ad_type = (krb5_authdatatype) ibuf;
+
+	    /* Get the length */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authdata->length = (int) ibuf;
+
+	    /* Get the string */
+	    if ((authdata->contents = (krb5_octet *)
+		 rpc_allocate(0,(size_t) (ibuf))) &&
+		!(kret = krb5_ser_unpack_bytes(authdata->contents,
+					       (size_t) ibuf,
+					       &bp, &remain))) {
+		if ((kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)))
+		    ibuf = 0;
+		if (ibuf == KV5M_AUTHDATA) {
+		    authdata->magic = KV5M_AUTHDATA;
+		    *buffer = bp;
+		    *lenremain = remain;
+		    *argp = (krb5_pointer) authdata;
+		}
+		else
+		    kret = EINVAL;
+	    }
+	    if (kret) {
+		if (authdata->contents)
+		    rpc_free(authdata->contents);
+		rpc_free(authdata);
+	    }
+	}
+    }
+    return(kret);
+}
+/*
+ * krb5_authenticator_internalize()	- Internalize the krb5_authenticator.
+ */
+static krb5_error_code
+krb5_authenticator_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_authenticator	*authenticator;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    int			i;
+    krb5_int32		nadata;
+    size_t		len;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_AUTHENTICATOR) {
+	kret = ENOMEM;
+
+	/* Get memory for the authenticator */
+	if ((remain >= (3*sizeof(krb5_int32))) &&
+	    (authenticator = (krb5_authenticator *) 
+	     rpc_allocate(0,sizeof(krb5_authenticator)))) {
+	    memset(authenticator, 0, sizeof(krb5_authenticator));
+
+	    /* Get ctime */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authenticator->ctime = (krb5_timestamp) ibuf;
+
+	    /* Get cusec */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authenticator->cusec = ibuf;
+
+	    /* Get seq_number */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    authenticator->seq_number = ibuf;
+	    
+	    kret = 0;
+
+	    /* Attempt to read in the client */
+	    kret = krb5_principal_internalize(kcontext,
+					   (krb5_pointer *)
+					   &authenticator->client,
+					   &bp,
+					   &remain);
+	    if (kret == EINVAL)
+		kret = 0;
+
+	    /* Attempt to read in the checksum */
+	    if (!kret) {
+		kret = krb5_checksum_internalize(kcontext,
+					       (krb5_pointer *)
+					       &authenticator->checksum,
+					       &bp,
+					       &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+
+	    /* Attempt to read in the subkey */
+	    if (!kret) {
+		kret = krb5_keyblock_internalize(kcontext,
+					       (krb5_pointer *)
+					       &authenticator->subkey,
+					       &bp,
+					       &remain);
+		if (kret == EINVAL)
+		    kret = 0;
+	    }
+
+	    /* Attempt to read in the authorization data count */
+	    if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
+		nadata = ibuf;
+		len = (size_t) (nadata + 1);
+
+		/* Get memory for the authorization data pointers */
+		if ((authenticator->authorization_data = (krb5_authdata **)
+		     rpc_allocate(0,sizeof(krb5_authdata *) * len))) {
+		    memset(authenticator->authorization_data, 0,
+			   sizeof(krb5_authdata *) * len);
+
+		    for (i=0; !kret && (i<nadata); i++) {
+			kret = krb5_address_internalize(kcontext,
+						       (krb5_pointer *)
+						       &authenticator->
+						       authorization_data[i],
+						       &bp,
+						       &remain);
+		    }
+
+		    /* Finally, find the trailer */
+		    if (!kret) {
+			kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+			if (!kret && (ibuf == KV5M_AUTHENTICATOR))
+			    authenticator->magic = KV5M_AUTHENTICATOR;
+			else
+			    kret = EINVAL;
+		    }
+		}
+	    }
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+		*argp = (krb5_pointer) authenticator;
+	    }
+	    else
+		krb5_free_authenticator(kcontext, authenticator);
+	}
+    }
+    return(kret);
+}
+
+#define	TOKEN_RADDR	950916
+#define	TOKEN_RPORT	950917
+#define	TOKEN_LADDR	950918
+#define	TOKEN_LPORT	950919
+#define	TOKEN_KEYBLOCK	950920
+#define	TOKEN_LSKBLOCK	950921
+#define	TOKEN_RSKBLOCK	950922
+
+/*
+ * krb5_auth_context_internalize()	- Internalize the krb5_auth_context.
+ */
+krb5_error_code
+krb5_auth_context_internalize(
+    krb5_context	kcontext,
+    krb5_pointer	*argp,
+    krb5_octet		**buffer,
+    size_t		*lenremain)
+{
+    krb5_error_code	kret;
+    krb5_auth_context	auth_context;
+    krb5_int32		ibuf;
+    krb5_octet		*bp;
+    size_t		remain;
+    krb5_int32		ivlen;
+    krb5_int32		tag;
+
+    bp = *buffer;
+    remain = *lenremain;
+    kret = EINVAL;
+    /* Read our magic number */
+    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
+	ibuf = 0;
+    if (ibuf == KV5M_AUTH_CONTEXT) {
+	kret = ENOMEM;
+
+	/* Get memory for the auth_context */
+	if ((remain >= (5*sizeof(krb5_int32))) &&
+	    (auth_context = (krb5_auth_context)
+	     rpc_allocate(0,sizeof(struct _krb5_auth_context)))) {
+	    memset(auth_context, 0, sizeof(struct _krb5_auth_context));
+
+	    /* Get auth_context_flags */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->auth_context_flags = ibuf;
+
+	    /* Get remote_seq_number */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->remote_seq_number = ibuf;
+
+	    /* Get local_seq_number */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->local_seq_number = ibuf;
+
+	    /* Get req_cksumtype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->req_cksumtype = (krb5_cksumtype) ibuf;
+
+	    /* Get safe_cksumtype */
+	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+	    auth_context->safe_cksumtype = (krb5_cksumtype) ibuf;
+
+	    /* Get length of i_vector */
+	    (void) krb5_ser_unpack_int32(&ivlen, &bp, &remain);
+
+	    if (ivlen) {
+		if ((auth_context->i_vector =
+		     (krb5_pointer) rpc_allocate(0,(size_t)ivlen)))
+		    kret = krb5_ser_unpack_bytes(auth_context->i_vector,
+						 (size_t) ivlen,
+						 &bp,
+						 &remain);
+		else
+		    kret = ENOMEM;
+	    }
+	    else
+		kret = 0;
+	    
+	    /* Peek at next token */
+	    tag = 0;
+	    if (!kret)
+		kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+
+	    /* This is the remote_addr */
+	    if (!kret && (tag == TOKEN_RADDR)) {
+		if (!(kret = krb5_authdata_internalize(kcontext,
+						     (krb5_pointer *)
+						     &auth_context->
+						     remote_addr,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the remote_port */
+	    if (!kret && (tag == TOKEN_RPORT)) {
+		if (!(kret = krb5_address_internalize(kcontext,
+						     (krb5_pointer *)
+						     &auth_context->
+						     remote_port,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the local_addr */
+	    if (!kret && (tag == TOKEN_LADDR)) {
+		if (!(kret = krb5_address_internalize(kcontext,
+						     (krb5_pointer *)
+						     &auth_context->
+						     local_addr,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the local_port */
+	    if (!kret && (tag == TOKEN_LPORT)) {
+		if (!(kret = krb5_address_internalize(kcontext,
+						     (krb5_pointer *)
+						     &auth_context->
+						     local_port,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the keyblock */
+	    if (!kret && (tag == TOKEN_KEYBLOCK)) {
+		if (!(kret = krb5_keyblock_internalize(kcontext,
+						     (krb5_pointer *)
+						     &auth_context->keyblock,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the local_subkey */
+	    if (!kret && (tag == TOKEN_LSKBLOCK)) {
+		if (!(kret = krb5_keyblock_internalize(kcontext,
+						     (krb5_pointer *)
+						     &auth_context->
+						     local_subkey,
+						     &bp,
+						     &remain)))
+		    kret = krb5_ser_unpack_int32(&tag, &bp, &remain);
+	    }
+
+	    /* This is the remote_subkey */
+	    if (!kret) {
+		if (tag == TOKEN_RSKBLOCK) {
+		    kret = krb5_keyblock_internalize(kcontext,
+						   (krb5_pointer *)
+						   &auth_context->
+						   remote_subkey,
+						   &bp,
+						   &remain);
+		}
+		else {
+		    /*
+		     * We read the next tag, but it's not of any use here, so
+		     * we effectively 'unget' it here.
+		     */
+		    bp -= sizeof(krb5_int32);
+		    remain += sizeof(krb5_int32);
+		}
+	    }
+
+	    /* Now find the authentp */
+	    if (!kret) {
+		if ((kret = krb5_authenticator_internalize(kcontext, 
+						    (krb5_pointer *)
+						    &auth_context->authentp,
+						    &bp,
+						    &remain))) {
+		    if (kret == EINVAL)
+			kret = 0;
+		}
+	    }
+
+	    /* Finally, find the trailer */
+	    if (!kret) {
+		kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
+		if (!kret && (ibuf != KV5M_AUTH_CONTEXT))
+		    kret = EINVAL;
+	    }
+	    if (!kret) {
+		*buffer = bp;
+		*lenremain = remain;
+		auth_context->magic = KV5M_AUTH_CONTEXT;
+		*argp = (krb5_pointer) auth_context;
+	    }
+	    else
+		krb5_auth_con_free(kcontext, auth_context);
+	}
+    }
+    return(kret);
+}
+#endif /*_NOT_USED_YET_*/
--- clean/net/sunrpc/gss_k5serialize.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5serialize.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,137 @@
+/*
+ *  linux/net/sunrpc/gss_k5serialize.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/krb5_krb/serialize.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+
+/*
+ * lib/krb5/krb/serialize.c
+ *
+ * Copyright 1995 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.
+ *
+ */
+
+/*
+ * Base routines to deal with serialization of Kerberos metadata.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+/*
+ * krb5_ser_pack_int32()	- Pack a 4-byte integer if space is availble.
+ *				  Update buffer pointer and remaining space.
+ */
+krb5_error_code 
+krb5_ser_pack_int32(
+    krb5_int32		iarg,
+    krb5_octet		 *  *bufp,
+    size_t		 *remainp)
+{
+    if (*remainp >= sizeof(krb5_int32)) {
+	(*bufp)[0] = (krb5_octet) ((iarg >> 24) & 0xff);
+	(*bufp)[1] = (krb5_octet) ((iarg >> 16) & 0xff);
+	(*bufp)[2] = (krb5_octet) ((iarg >> 8) & 0xff);
+	(*bufp)[3] = (krb5_octet) (iarg & 0xff);
+	*bufp += sizeof(krb5_int32);
+	*remainp -= sizeof(krb5_int32);
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+ 
+/*
+ * krb5_ser_pack_bytes()	- Pack a string of bytes.
+ */
+krb5_error_code 
+krb5_ser_pack_bytes(
+    krb5_octet	 *ostring,
+    size_t	osize,
+    krb5_octet	 *  *bufp,
+    size_t	 *remainp)
+{
+    if (*remainp >= osize) {
+	memcpy(*bufp, ostring, osize);
+	*bufp += osize;
+	*remainp -= osize;
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+ 
+/*
+ * krb5_ser_unpack_int32()	- Unpack a 4-byte integer if it's there.
+ */
+krb5_error_code 
+krb5_ser_unpack_int32(
+    krb5_int32	 *intp,
+    krb5_octet	 *  *bufp,
+    size_t	 *remainp)
+{
+    if (*remainp >= sizeof(krb5_int32)) {
+	*intp = (((krb5_int32) ((unsigned char) (*bufp)[0]) << 24) |
+		 ((krb5_int32) ((unsigned char) (*bufp)[1]) << 16) |
+		 ((krb5_int32) ((unsigned char) (*bufp)[2]) << 8) |
+		 ((krb5_int32) ((unsigned char) (*bufp)[3])));
+	*bufp += sizeof(krb5_int32);
+	*remainp -= sizeof(krb5_int32);
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
+ 
+/*
+ * krb5_ser_unpack_bytes()	- Unpack a byte string if it's there.
+ */
+krb5_error_code 
+krb5_ser_unpack_bytes(
+    krb5_octet	 *istring,
+    size_t	isize,
+    krb5_octet	 *  *bufp,
+    size_t	 *remainp)
+{
+    if (*remainp >= isize) {
+	memcpy(istring, *bufp, isize);
+	*bufp += isize;
+	*remainp -= isize;
+	return(0);
+    }
+    else
+	return(ENOMEM);
+}
--- clean/net/sunrpc/gss_k5unseal.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5unseal.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,423 @@
+/*
+ *  linux/net/sunrpc/gss_k5unseal.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5unseal.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * 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 FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  FundsXpress makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+   conf_state is only valid if SEAL. */
+
+u32
+kg_unseal_v1(
+    u32 *minor_status,
+    krb5_gss_ctx_id_rec *ctx,
+    unsigned char *ptr,
+    int bodysize,
+    GSS_BUFFER_T *message_buffer,
+    int *conf_state,
+    int *qop_state,
+    int toktype)
+{
+    krb5_error_code code;
+    int tmsglen;
+    int conflen = 0;
+    int signalg;
+    int sealalg;
+    GSS_BUFFER_T token;
+    krb5_checksum cksum;
+    krb5_checksum md5cksum;
+    krb5_data plaind;
+    char *data_ptr;
+    krb5_timestamp now;
+    unsigned char *plain = NULL;
+    int cksum_len = 0;
+    int plainlen = 0;
+    int direction;
+    krb5_int32 seqnum;
+    u32 retval;
+    size_t sumlen;
+
+    dprintk("RPC: kg_unseal_v1\n");
+    if (toktype == KG_TOK_SEAL_MSG) {
+        message_buffer->len = 0;
+        message_buffer->data = NULL;
+    }
+
+    /* get the sign and seal algorithms */
+
+    signalg = ptr[0] + (ptr[1]<<8);
+    sealalg = ptr[2] + (ptr[3]<<8);
+
+    /* Sanity checks */
+
+    if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if ((toktype != KG_TOK_SEAL_MSG) &&
+	(sealalg != 0xffff)) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* in the current spec, there is only one valid seal algorithm per
+       key type, so a simple comparison is ok */
+
+    if ((toktype == KG_TOK_SEAL_MSG) &&
+	!((sealalg == 0xffff) ||
+	  (sealalg == ctx->sealalg))) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+    /* there are several mappings of seal algorithms to sign algorithms,
+       but few enough that we can try them all. */
+
+    if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
+	(ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
+	(ctx->sealalg == SEAL_ALG_DES3KD &&
+	 signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) {
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+/* starting with a single alg */
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+	cksum_len = 8;
+	break;
+    default:
+	*minor_status = 0;
+	return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (toktype == KG_TOK_SEAL_MSG)
+	tmsglen = bodysize-(14+cksum_len);
+
+    /* get the token parameters */
+
+    /* decode the message, if SEAL */
+
+    if (toktype == KG_TOK_SEAL_MSG) {
+        dprintk("RPC: kg_unseal_v1 KG_TOK_SEAL_MSG\n");
+
+
+#if 0 /* XXX - get sign working first*/
+
+	if (sealalg != 0xffff) {
+	    if ((plain = (unsigned char *) rpc_allocate(0,tmsglen)) == NULL) {
+		*minor_status = ENOMEM;
+		return(GSS_S_FAILURE);
+	    }
+
+	    if ((code = kg_decrypt(ctx->enc, KG_USAGE_SEAL, NULL,
+				   ptr+14+cksum_len, plain, tmsglen))) {
+		rpc_free(plain);
+		*minor_status = code;
+		return(GSS_S_FAILURE);
+	    }
+	} else {
+	    plain = ptr+14+cksum_len;
+	}
+
+	plainlen = tmsglen;
+
+	if ((sealalg == 0xffff) && ctx->big_endian) {
+	    token.len = tmsglen;
+	} else {
+	    conflen = kg_confounder_size(ctx->enc);
+	    token.len = tmsglen - conflen - plain[tmsglen-1];
+	}
+
+	if (token.len) {
+	    if ((token.data = (void *) rpc_allocate(0,token.len)) == NULL) {
+		if (sealalg != 0xffff)
+		    rpc_free(plain);
+		*minor_status = ENOMEM;
+		return(GSS_S_FAILURE);
+	    }
+	    memcpy(token.data, plain+conflen, token.len);
+	}
+#endif /*0*/
+
+    } else if (toktype == KG_TOK_SIGN_MSG) {
+        dprintk("RPC: kg_unseal_v1 KG_TOK_SIGN_MSG\n");
+	token = *message_buffer;
+	plain = token.data;
+	plainlen = token.len;
+    } else {
+	token.len = 0;
+	token.data = NULL;
+	plain = token.data;
+	plainlen = token.len;
+    }
+
+   dprintk("RPC kg_unseal_v1: token.len %d plainlen %d\n",token.len,plainlen);
+
+    /* compute the checksum of the message */
+
+    /* initialize the the cksum */
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
+        break;
+    default:
+        *minor_status = 0;
+        return(GSS_S_DEFECTIVE_TOKEN);
+    }
+
+    if ((code = k5_get_checksum_length(md5cksum.checksum_type, &sumlen)))
+        return(code);
+    md5cksum.length = sumlen;
+
+    switch (signalg) {
+    case SGN_ALG_DES_MAC_MD5:
+       dprintk("RPC kg_unseal_v1 SGN_ALG_DES_MAC_MD5\n");
+    /* compute the checksum of the message.
+    * 8 = bytes of token body to be checksummed according to spec 
+    */
+        if (! (data_ptr = (void *)
+            rpc_allocate(0,8 + (ctx->big_endian ? token.len : plainlen)))) {
+            if (sealalg != 0xffff)
+                rpc_free(plain);
+            if (toktype == KG_TOK_SEAL_MSG)
+                rpc_free(token.data);
+                *minor_status = ENOMEM;
+                return(GSS_S_FAILURE);
+        }
+
+    (void) memcpy(data_ptr, ptr-2, 8);
+	if (ctx->big_endian)
+	    (void) memcpy(data_ptr+8, token.data, token.len);
+	else
+	    (void) memcpy(data_ptr+8, plain, plainlen);
+
+	plaind.length = 8 + (ctx->big_endian ? token.len : plainlen);
+	plaind.data = data_ptr;
+
+  dprintk("RPC:kg_unseal calling make_checksum with PLAIN TEXT\n");
+  print_hexl((u32 *)plaind.data,(plaind.length >> 2),0);
+
+	code = krb5_c_make_checksum(0,md5cksum.checksum_type,
+				    ctx->seq, KG_USAGE_SIGN,
+				    &plaind, &md5cksum);
+
+	rpc_free(data_ptr);
+
+	if (code) {
+	    if (toktype == KG_TOK_SEAL_MSG)
+		rpc_free(token.data);
+	    *minor_status = code;
+	    return(GSS_S_FAILURE);
+	}
+
+/*  see comments in gss_k5seal.c
+* we hard code the NULL ivec
+	if ((code = gss_k5encrypt(ctx->seq, KG_USAGE_SEAL,
+			       (g_OID_equal(ctx->mech_used, &gss_mech_krb5_oid) ?
+				ctx->seq->contents : NULL),
+			       md5cksum.contents, md5cksum.contents,16))) {
+*/
+	if ((code = gss_k5encrypt(ctx->seq, KG_USAGE_SEAL,
+				     NULL,
+			       md5cksum.contents, 
+             md5cksum.contents,16))) {
+	    rpc_free(md5cksum.contents);
+	    if (toktype == KG_TOK_SEAL_MSG)
+		rpc_free(token.data);
+	    *minor_status = code;
+	    return GSS_S_FAILURE;
+	}
+
+
+	if (signalg == 0)
+	    cksum.length = 8;
+	else
+	    cksum.length = 16;
+	cksum.contents = md5cksum.contents + 16 - cksum.length;
+
+	dprintk("RPC: kg_unseal_vi: memcmp digest cksum.length %d:\n",cksum.length);
+	dprintk("          md5cksum.contents\n");
+	print_hexl((u32 *)md5cksum.contents,16,0);
+	dprintk("          cksum.contents:\n");
+	print_hexl((u32 *)cksum.contents,cksum.length,0);
+	{
+	u32 *p; 
+
+	(u8*)p = ptr+14;
+	dprintk("          ptr+14:\n");
+	print_hexl(p,cksum.length,0);
+	}
+
+	code = memcmp(cksum.contents, ptr+14, cksum.length);
+	break;
+    default:
+	*minor_status = 0;
+	return(GSS_S_DEFECTIVE_TOKEN);
+    }
+
+    rpc_free(md5cksum.contents);
+    if (sealalg != 0xffff)
+	rpc_free(plain);
+
+    /* compare the computed checksum against the transmitted checksum */
+
+    if (code) {
+	if (toktype == KG_TOK_SEAL_MSG)
+	    rpc_free(token.data);
+	*minor_status = 0;
+	return(GSS_S_BAD_SIG);
+    }
+
+    /* it got through unscathed.  Make sure the context is unexpired */
+
+    if (toktype == KG_TOK_SEAL_MSG)
+	*message_buffer = token;
+
+    if (conf_state)
+	*conf_state = (sealalg != 0xffff);
+
+    if (qop_state)
+	*qop_state = GSS_C_QOP_DEFAULT;
+
+#if _USERLAND_
+    if ((code = krb5_timeofday(&now))) {
+	*minor_status = code;
+	return(GSS_S_FAILURE);
+    }
+#endif/*0*/
+    now = jiffies;
+
+    if (now > ctx->endtime) {
+	*minor_status = 0;
+	return(GSS_S_CONTEXT_EXPIRED);
+    }
+
+    /* do sequencing checks */
+
+    if ((code = kg_get_seq_num(ctx->seq, ptr+14, ptr+6, &direction,
+			       &seqnum))) {
+	if (toktype == KG_TOK_SEAL_MSG)
+	    rpc_free(token.data);
+	*minor_status = code;
+	return(GSS_S_BAD_SIG);
+    }
+
+    if ((ctx->initiate && direction != 0xff) ||
+	(!ctx->initiate && direction != 0)) {
+	if (toktype == KG_TOK_SEAL_MSG)
+	    rpc_free(token.data);
+	*minor_status = G_BAD_DIRECTION;
+	return(GSS_S_BAD_SIG);
+    }
+
+    retval = g_order_check(&(ctx->seqstate), seqnum);
+
+    /* success or ordering violation */
+
+
+    *minor_status = 0;
+    return(retval);
+}
+
+/* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX
+   conf_state is only valid if SEAL. */
+
+u32
+kg_unseal(
+    u32 *minor_status,
+    GSS_CTX_ID_T * context_handle,
+    GSS_BUFFER_T *input_token_buffer,
+    GSS_BUFFER_T * message_buffer,
+    int *conf_state,
+    int *qop_state,
+    int toktype)
+{
+    krb5_gss_ctx_id_rec *ctx;
+    unsigned char *ptr;
+    int bodysize;
+    int err;
+
+    ctx = k_ctx(context_handle);
+    
+    if (! ctx->established) {
+	*minor_status = KG_CTX_INCOMPLETE;
+	return(GSS_S_NO_CONTEXT);
+    }
+
+    ptr = (unsigned char *) input_token_buffer->data;
+
+    /* parse the token, leave the data in message_buffer, setting conf_state */
+    if ((err = g_verify_token_header((GSS_OID *)ctx->mech_used,
+				      &bodysize, &ptr, toktype,
+				      input_token_buffer->len))!=0) {
+        *minor_status = err;
+        return(GSS_S_DEFECTIVE_TOKEN);
+    }
+    return(kg_unseal_v1(minor_status, ctx, ptr, bodysize,
+			    message_buffer, conf_state, qop_state,
+			    toktype));
+}
--- clean/net/sunrpc/gss_k5util_seqnum.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_k5util_seqnum.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,98 @@
+/*
+ *  linux/net/sunrpc/gss_k5util_seqnum.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/util_seqnum.c
+ *
+ *  Copyright (c) 2000 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ * 
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+
+krb5_error_code
+kg_make_seq_num(
+     krb5_keyblock *key,
+     int direction,
+     krb5_int32 seqnum,
+     unsigned char *cksum,
+     unsigned char *buf)
+{
+   unsigned char plain[8];
+
+   plain[0] = (unsigned char) (seqnum&0xff);
+   plain[1] = (unsigned char) ((seqnum>>8)&0xff);
+   plain[2] = (unsigned char) ((seqnum>>16)&0xff);
+   plain[3] = (unsigned char) ((seqnum>>24)&0xff);
+
+   plain[4] = direction;
+   plain[5] = direction;
+   plain[6] = direction;
+   plain[7] = direction;
+
+   return(gss_k5encrypt(key, KG_USAGE_SEQ, cksum, plain, buf, 8));
+}
+
+krb5_error_code kg_get_seq_num(
+     krb5_keyblock *key,
+     unsigned char *cksum,
+     unsigned char *buf,
+     int *direction,
+     krb5_int32 *seqnum)
+{
+    krb5_error_code code;
+    unsigned char plain[8];
+
+    dprintk("kg_get_seq_num: \n");
+
+    if ((code = gss_k5decrypt(key, KG_USAGE_SEQ, cksum, buf, plain, 8))){
+        printk("kg_get_seq_num: gss_k5decrypt failed with return: %d\n",code);
+        return(code);
+    }
+   
+
+    if ((plain[4] != plain[5]) ||
+        (plain[4] != plain[6]) ||
+        (plain[4] != plain[7]))
+        return((krb5_error_code) KG_BAD_SEQ);
+
+    *direction = plain[4];
+
+    *seqnum = ((plain[0]) |
+        (plain[1]<<8) |
+        (plain[2]<<16) |
+        (plain[3]<<24));
+
+    return(0);
+}
--- clean/net/sunrpc/gss_mic.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_mic.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,123 @@
+/*
+ *  linux/net/sunrpc/gss_mic.c
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* experimental interface to call the kernel crypto api with sha1 hash */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+#include <linux/crypto.h>
+                                      
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+
+/* 
+* Function: gss_verify_mic
+* 
+* Description: hash signbuf and decode verifier token and compare 
+*              to the value in checksum. NOTE: caller validates context handle.
+* NOTE: hard wired krb5 version.
+*/ 
+
+int
+gss_verify_mic(u32 *minor_status, GSS_CTX_ID_T *contextid, GSS_BUFFER_T *signbuf, GSS_BUFFER_T *checksum, u32 *qstate)
+{
+    int maj_stat = 0;
+    int qop_state;
+
+    dprintk("GSS_VERIFY_MIC\n");
+
+    /* caller validated handle. should switch on ctx_handle mechanism 
+     * but hardcode k5 for now
+     */
+    print_krb5_gss_ctx_id_rec(k_ctx(contextid));
+
+    dprintk("VERIFY MIC calling kg_unseal\n");
+
+    maj_stat = kg_unseal(minor_status, contextid,
+                      checksum,signbuf,
+                      NULL, &qop_state, KG_TOK_MIC_MSG);
+    if (!maj_stat && qop_state)
+        *qstate = qop_state;
+
+    dprintk("VERIFY MIC returning maj:min %d:%d\n",*minor_status,maj_stat);
+    return maj_stat;
+}
+
+
+
+/* 
+* Function: gss_get_mic
+* 
+* Description: hash messages_buffer and return gss verify token.
+*              NOTE: caller validates context handle.
+* NOTE: hard wired krb5 version.
+*/ 
+
+int
+gss_get_mic(u32 *minor_status, GSS_CTX_ID_T *contextid, u32 qop, GSS_BUFFER_T *message_buffer, GSS_BUFFER_T *message_token)
+{
+int err = 0,i;
+unsigned char *pp;
+
+    dprintk("GSS_GETMIC\n");
+
+    /* caller validates context handle.  should switch on ctx_handle
+     *  mechanism , but hardcode k5 for now
+    */
+    print_krb5_gss_ctx_id_rec(k_ctx(contextid));
+
+    if(!message_buffer->data) return -EINVAL;
+
+    dprintk("GSS_GETMIC: message_buffer->len %d\n",message_buffer->len);
+    pp = message_buffer->data;
+    for(i=0;i<message_buffer->len;i++)
+        dprintk("%02x",*pp++);
+    dprintk("\n");
+
+    dprintk("GETMIC calling kg_seal\n");
+    err = kg_seal(0,minor_status,contextid,0,
+                   qop,message_buffer, NULL,
+                   message_token, KG_TOK_SIGN_MSG);
+
+    dprintk("GETMIC kg_seal return: %d \n",err);
+
+  return err;
+}
--- clean/net/sunrpc/gss_svc_cache.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_svc_cache.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,248 @@
+/*
+ *  linux/net/sunrpc/gss_svc_cache.c
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *  Dug Song       <dugsong@monkey.org>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+/* import the krb5 gss context into the kernel for use with gss crypto
+ * routines.
+ * for now, only import the pieces of the context actively used by
+ * gss_verify_mic and gss_get_mic.
+ *
+ * typedef struct _krb5_gss_ctx_id_rec_kernel {
+ *    int initiate;
+ *    int seed_init;
+ *    unsigned char seed[16];
+ *    krb5_keyblock *subkey;
+ *    int sealalg;
+ *    krb5_keyblock *enc;
+ *    krb5_keyblock *seq;
+ *    krb5_timestamp endtime;
+ *    void *seqstate;
+ *    int established;
+ *    int big_endian;
+ *    GSS_OID *mech_used;
+ * } krb5_gss_ctx_id_rec_kernel, *krb5_gss_ctx_id__kernel_t;
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/auth_gss.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+static struct gss_svc_ctx_mapping	svc_ctx_map;
+
+/*
+ ***************** gss context cache functions *********************
+ *
+ * On the server, the gss_svc_ctx_mapping struct holds gss_ctx_cacheents 
+ * hashed by cacheent pointer which is stored in the server rpc_gss_cred
+ *
+ * client and server share gss_ctx_cacheent alloc and free.
+ *
+ */
+
+
+void
+gss_svc_ctx_init(void)
+{
+        int i;
+
+	dprintk("GSS_SVC_CTX_INIT\n");
+        rwlock_init(&svc_ctx_map.lock);
+        for (i = 0; i < GSS_HASH_SIZE; i++) {
+                INIT_LIST_HEAD(&svc_ctx_map.gss_ctx_cache[i]);
+        }
+}
+
+
+static inline void
+gss_svc_ctx_insert(struct gss_ctx_cacheent *p)
+{
+	unsigned int ptrhash = (unsigned int)p << 16;
+        unsigned int ctx_hashval = (ptrhash & GSS_HASH_MASK);
+
+	dprintk("gss_svc_ctx_insert: ctx_hashval: %d\n",ctx_hashval);
+        /* caller must hold writelock */
+        atomic_set(&p->gcc_refcount, 1);    /* gcc_refcount==1 indicates in use by the cache */
+        list_add(&p->gss_ctx_cache, &svc_ctx_map.gss_ctx_cache[ctx_hashval]);
+}
+
+void
+gss_svc_clear_ctx_map(struct gss_svc_ctx_mapping *map)
+{
+	int i;
+	struct list_head *l;
+	struct gss_ctx_cacheent *p;
+
+	for (i = 0; i < GSS_HASH_SIZE; i++) {
+		l = &map->gss_ctx_cache[i];
+		while (!list_empty(l)) {
+			write_lock(&map->lock);
+			p = list_entry(l->next, struct gss_ctx_cacheent, gss_ctx_cache);
+			list_del(&p->gss_ctx_cache);
+	/* Since gss_ctx_put() can block, it can only be called 
+	 *safely if the spinlock is not held. 
+	 */
+			write_unlock(&map->lock);
+			gss_ctx_put(p);
+		}
+	}
+}
+
+void
+gss_svc_ctx_shutdown(void)
+{
+        dprintk("gss_svc_ctx_shutdown: starting\n");
+        gss_svc_clear_ctx_map(&svc_ctx_map);
+        dprintk("gss_svc_ctx_shutdown: done\n");
+}
+
+
+/* Function: gss_svc_get_context()
+ *
+ * Description: wrapper for gssd_import_sec_context(). 
+ * A new gss_ctx_cacheent is created to store the security context 
+ * obtained from gssd.
+ * 
+ * Parameters:
+ *   INPUT
+ *   ctx: the GSS_CTX_ID_T returned from gssd_init_sec_context() or 
+ *        gssd_accept_sec_context(). this is a union context
+ *        that contains the mech OID as well as the internal ctx id
+ *   OUTPUT
+ *   ctx: pointer to the created gss_ctx_cacheent that contains the 
+ *        imported context.
+ */
+
+u32
+gss_svc_get_context(u32 *maj_stat, u32* min_stat, GSS_CTX_ID_T *ctx)
+{
+	struct gss_ctx_cacheent *cep = NULL;
+	GSS_BUFFER_T	buf;
+	u32 ret = 0;
+
+	dprintk("RPC: gss_svc_get_context: internal ctx: %p\n",c_ctx(ctx));
+
+	if (gssd_import_sec_context(maj_stat,min_stat,ctx,&buf) < 0)
+		goto outerr;
+
+	dprintk("RPC: gss_svc_get_context: maj_stat %d min_stat %d\n",*maj_stat, *min_stat);
+	/* allocate cacheent */
+	if(!(cep = gss_ctx_alloc())) {
+		*min_stat = -ENOMEM;	
+		goto outerr;
+	}
+
+	/* internalize context: should switch on mechanism... */
+	if((ret = k5_gss_import_sec_context(min_stat,&buf,&cep->gcc_ctx)) !=0)
+		goto outerr;
+
+	if((*min_stat = gss_get_ctx_mech(&cep->gcc_mech,ctx)) !=0)
+		goto outerr;	
+	cep->gcc_qop = GSS_C_QOP_DEFAULT;
+
+	if((*min_stat = gss_set_ctx(ctx,cep)))
+		goto outerr;	
+
+	/* insert cacheent into cache */
+	write_lock(&svc_ctx_map.lock);
+	gss_svc_ctx_insert(cep);
+	write_unlock(&svc_ctx_map.lock);
+
+	print_krb5_gss_ctx_id_rec(k_ctx(ctx));
+out:
+	return *min_stat;
+outerr:
+	dprintk("RPC: gss_svc_get_context: err %d\n",*min_stat);
+	if(cep != NULL)
+		gss_ctx_free(cep);
+	goto out;
+}
+
+/* Function: gss_svc_searchbyctx
+ *
+ * Description: search server context cache for 
+ * context.
+ */
+
+static inline struct gss_ctx_cacheent *
+gss_svc_searchbyctx(GSS_CTX_ID_T *ctx_id)
+{
+	struct gss_ctx_cacheent *p,*cep = c_ctx(ctx_id);
+        unsigned int ptrhash = (unsigned int)cep << 16;
+        unsigned int ctx_hashval = (ptrhash & GSS_HASH_MASK);
+        struct list_head *l;
+
+        /* caller must hold readlock */
+        list_for_each(l, &svc_ctx_map.gss_ctx_cache[ctx_hashval]) {
+                p = list_entry(l, struct gss_ctx_cacheent, gss_ctx_cache);
+                if (p == cep){
+		 	dprintk("gss_svc_searchbyctx returning p: %p\n",p);
+                        return p;
+		}
+        }
+	dprintk("gss_svc_searchbyctx returning NULL\n");
+        return NULL;
+}
+
+
+/* Funciton: gss_svc_validate_context(GSS_CTX_ID_T *ctx_id)
+ *
+ * Description: lookup ctx_id in svc_ctx_map. return boolean result
+ */
+u32
+gss_svc_validate_context(GSS_CTX_ID_T *ctx_id)
+{
+	struct gss_ctx_cacheent *p = NULL;
+
+	read_lock(&svc_ctx_map.lock);
+	p = gss_svc_searchbyctx(ctx_id);
+	read_unlock(&svc_ctx_map.lock);
+	if(!p){ 
+		dprintk("gss_svc_validate_context: context NOT found\n");
+		return 0;
+	}
+	else{ 
+	 	dprintk("gss_svc_validate_context: found context: %p\n",p);
+		return 1;
+	}
+}
--- clean/net/sunrpc/gss_union.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_union.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,165 @@
+/*
+ *  linux/net/sunrpc/gss_union.c
+ *
+ *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic code
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ */
+
+/*
+ * Copyright 1993 by OpenVision Technologies, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appears in all copies and
+ * that both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OpenVision not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. OpenVision makes no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */ 
+
+
+/* 
+ * This code is to export the security context referenced by the 
+ * ctx_id from the user space gss code, destroy the user space 
+ * context, and place the context in xdr form into a buffer, ready
+ * to be sent to the kernel.
+ * 
+ * The usual way to do this is to call the gss_export_sec_context() 
+ * routine which extracts (and deletes) the context from on process
+ * into a buffer suitable for on the wire.  This buffer is then
+ * presented to the gss_import_sec_context routine which does the 
+ * opposite process.
+ *
+ * My problem is that there is no gss code in the kernel, and the
+ * krb5 version of gss_export_sec_context() 'externalizes' the context
+ * in a way similar to xdr, but with private routines. 
+ * This routine receives the union_ctx_id, and switches on the 
+ * mechanism to call a routine that exports the context in an xdr'ed form,
+ * which can be decoded by the kernel xdr code.
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/socket.h>
+#include <linux/sunrpc/auth_gss.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+GSS_OID gss_mech_krb5_oid =
+   {9, "\052\206\110\206\367\022\001\002\002"};
+
+#if SPKM
+GSS_OID gss_mech_spkm3_oid =
+   {7, "\052\006\001\005\005\001\003"};
+#endif /*SPKM*/
+
+static const int sup_sec_len = 1;
+static const struct sup_sec_triple sec_triples[] =  {
+	{&gss_mech_krb5_oid,0,1}
+};
+
+void
+print_sec_triples(GSS_OID *oid,u32 qop,u32 service){
+	dprintk("RPC: print_sec_triples\n");
+	dprintk("                     oid_len %d\n  oid :\n",oid->len);
+	print_hexl((u32 *)oid->data,oid->len,0);
+	dprintk("                     qop %d\n",qop);
+	dprintk("                     service %d\n",service);
+}
+
+/* Function: gss_cmp_triples
+ *
+ * Description: search sec_triples for a matching security triple
+ * return 1 if match, else 0
+ */
+int
+gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service)
+{
+int i;
+GSS_OID oid;
+
+	oid.len = oid_len;
+	oid.data = oid_data;
+
+	dprintk("RPC: gss_cmp_triples \n");
+	print_sec_triples(&oid,qop,service);
+	for(i=0;i<sup_sec_len;i++){
+		if((g_OID_equal(&oid,sec_triples[i].oid)) &&
+		   (qop == sec_triples[i].qop)          &&
+		   (service == sec_triples[i].service)) { 
+		dprintk("RPC: gss_cmp_triples return 1 \n");
+		return 1;
+		}
+  }
+	dprintk("RPC: gss_cmp_triples return 0 \n");
+	return 0;
+}
+
+/* Function: gss_get_context_mech()
+ * 
+ * Description: return the union context mech_type
+ * the union context is set by the user space k5 
+ * lib/gssapi/mechglue code called via gssd.
+ */
+u32
+gss_get_ctx_mech(GSS_OID *mech, GSS_CTX_ID_T *ctx_id)
+{
+	gss_union_ctx_id_t ctx;
+
+	dprintk("gss_get_ctx_mech \n");
+  if(!ctx_id){
+		dprintk("RPC: gss_get_ctx_mech NULL ctx_id\n");
+		return -EINVAL;
+	}
+	ctx = (gss_union_ctx_id_t)ctx_id->data; 
+	mech->len = ctx->mech_type.len;
+	mech->data = ctx->mech_type.data;
+	dprintk("gss_get_ctx_mech returning\n");
+	return(0);
+}
+
+/* Function gss_set_ctx()
+ * 
+ * Description:  called after gss_import_sec_context() 
+ * to change the union ctx internal_ctx_id 
+ * from a pointer to the user space context used by gssd
+ * to a kernel gss_cacheent entry.  
+ */
+u32
+gss_set_ctx(GSS_CTX_ID_T *ctx_id,struct gss_ctx_cacheent *cep)
+{
+
+	gss_union_ctx_id_t ctx;
+
+	dprintk("gss_set_ctx\n");
+
+  if(!ctx_id){
+		dprintk("RPC: gss_set_ctx NULL ctx_id\n");
+		return -EINVAL;
+	}
+	ctx = (gss_union_ctx_id_t)ctx_id->data; 
+	ctx->internal_ctx_id.data = (char *)cep;
+	ctx->internal_ctx_id.len = 4;
+
+	dprintk("gss_set_ctx internal %p cep %p\n",c_ctx(ctx_id),cep);
+	return(0);
+}
+
--- clean/net/sunrpc/gss_util_crypto.c	Tue Feb 26 12:04:09 2002
+++ dirty/net/sunrpc/gss_util_crypto.c	Mon Feb 25 12:08:45 2002
@@ -0,0 +1,146 @@
+/*
+ *  linux/net/sunrpc/gss_util_crypto.c
+ *
+ *  Copyright (c) 2001 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/gss_krb5_types.h>
+#include <linux/crypto.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY        RPCDBG_AUTH
+#endif
+
+
+                                      
+/* linux crypto framework uses names to lookup supported ciphers and 
+ * digests. these structures map the kerberos5 digest and cipher types
+ * to the linux crypto specific names.
+ */
+
+extern struct krb5_hash_provider krb5_hash_md5;
+
+/* name mapping for digests */
+const krb5_2_linux_digest digest_list[] = {
+    { CKSUMTYPE_RSA_MD5,
+      "md5",
+      &krb5_hash_md5,
+      (struct krb5_keyhash_provider *)NULL}
+};
+
+const int digest_list_length =
+sizeof(digest_list)/sizeof(krb5_2_linux_digest);
+
+/* name mapping for encryption algorithms */
+const krb5_2_linux_keytypes cipher_list[] = {
+    { ENCTYPE_DES_CBC_RAW,
+      "des-cbc","NULL"}
+};
+
+
+const int keytype_length =
+sizeof(cipher_list)/sizeof(krb5_2_linux_keytypes);
+
+int
+find_digest(krb5_cksumtype type)
+{
+int i;
+    dprintk("RPC:find_digest type %d\n",type);
+    for(i=0;i<digest_list_length;i++){
+        if(digest_list[i].ctype == type){
+            dprintk("RPC:find_digest loop i %d ctype %d\n",i,digest_list[i].ctype);
+            break;
+        }
+    }
+    if(i == digest_list_length) 
+        return -1;
+    return i;
+}
+
+int
+find_enctype(krb5_enctype enctype)
+{
+int i;
+    dprintk("RPC:find_enctype type %d\n",enctype);
+    for(i=0;i<keytype_length;i++){
+    if(cipher_list[i].enctype == enctype)
+        break;
+    }
+    if(i == keytype_length) 
+        return -1;
+    return i;
+}
+
+int
+k5_get_blocksize(krb5_enctype enctype, size_t *blocksize)
+{
+int i;
+struct cipher_implementation *ci = NULL;
+
+    dprintk("RPC: k5_get_blocksize type %d \n",enctype); 
+    i = find_enctype(enctype);
+    if(i < 0)
+        return(-EINVAL);
+
+    if(cipher_list[i].seal_name) 
+        ci = find_cipher_by_name(cipher_list[i].seal_name,1); 
+    if(!ci)
+        return(-EINVAL);
+    *blocksize = ci->blocksize;	    
+    dprintk("RPC: k5_get_blocksize blocksize %d\n",*blocksize); 
+    return 0;
+}
+
+int
+k5_get_checksum_length(krb5_cksumtype cksmtype, size_t *length)
+{
+int i;
+struct digest_implementation *di = NULL;
+
+    dprintk("RPC: k5_get_checksum_length type %d\n",cksmtype);
+    i = find_digest(cksmtype);
+    if(i < 0)
+        return(-EINVAL);
+
+    dprintk("RPC: k5_get_checksum_length calling find_digest_by_name\n");
+    if(digest_list[i].digest_name) 
+        di = find_digest_by_name(digest_list[i].digest_name,1);
+    if(!di)
+        return(-EINVAL);
+    *length = di->blocksize;
+    dprintk("RPC: k5_get_checksum_length length %d\n",*length);
+    return 0;
+}
--- clean/fs/nfs4fs/renewd.c	Tue Feb 26 12:00:35 2002
+++ dirty/fs/nfs4fs/renewd.c	Tue Feb 26 11:45:29 2002
@@ -104,19 +104,11 @@
 	
 	nfsv4_printk(lease2, "RENEWD: making RENEW call\n");
 
-#ifdef CONFIG_SUNRPC_GSS
- /* for AUTH_GSS tell rpciod which creds to use  - 
-  * AUTH_SYS and AUTH_NONE, renewd will run as root */
-  printk("HARDCODE HACK! will soon set to machine creds. for now, pick a user with kerberos5 credentials! renewd setting proxy_uid/gid [%d:%d]\n",23975,100);
-  task->tk_client->cl_auth->proxy_uid = 23975;
-  task->tk_client->cl_auth->proxy_gid = 100;
-  task->tk_flags |= RPC_TASK_PROXYCREDS;
-#endif /* CONFIG_SUNRPC_GSS */
-
 	/* Set up the RENEW call... */
 	if (nfs4fs_setup_async(&cp, sb, "renewd", NULL, renew_handler, NULL))
 		goto fail;
 	nfs4fs_setup_renew(cp);
+	cp->flags |= CA_RUN_AS_MACHINE;
 	if (nfs4fs_call_async(cp))
 		goto fail;
 
--- clean/fs/nfs4fs/proc.c	Tue Feb 26 12:00:35 2002
+++ dirty/fs/nfs4fs/proc.c	Mon Feb 25 16:14:06 2002
@@ -229,6 +229,8 @@
 	/*
 	 * Success; our request will now be XDR encoded and put on the wire.
 	 */
+	if(cp->flags & CA_RUN_AS_MACHINE)
+		task->tk_flags |= RPC_TASK_MACHINE_CREDS;
 	cp->timestamp = jiffies;
 	rpc_call_setup(task, &msg, 0);
 	return;
@@ -379,7 +381,7 @@
 	* Spawn a child task to negotiate rpc_clnt auth handle
 	*/
 
-printk("ANDROS: calling ALLOC before spawn_secinfo\n");
+	nfsv4_printk(secinfo,"NFSv4: calling ALLOC before spawn_secinfo\n");
 
 	if((op = NFS4_ALLOC(sizeof(struct nfs4fs_op))) == NULL)
 		return; /* XXX is this right? */
--- clean/fs/nfs4fs/dir.c	Tue Feb 26 12:00:35 2002
+++ dirty/fs/nfs4fs/dir.c	Mon Feb 25 16:17:06 2002
@@ -88,7 +88,7 @@
 	NFS4_ASSERT(kernel_locked());
 
 	do_reval = nfs4_need_reval(parent_inode);	
-	compound.u.secinfo.dentry = dentry;
+	compound.secinfo_dentry = dentry;
 
 	nfs4fs_setup_compound(&compound, dentry->d_sb, "do_lookup()");
 	nfs4fs_setup_putfh(&compound, parent_inode);
--- clean/include/linux/nfs4/nfs4fs.h	Tue Feb 26 12:00:35 2002
+++ dirty/include/linux/nfs4/nfs4fs.h	Mon Feb 25 16:16:31 2002
@@ -330,10 +330,6 @@
 			struct file *		file;
 		} commit;
 		struct {
-			/* XXX: this arm of the union can now be removed, no? */
-			struct dentry *   dentry;
-		} secinfo;
-		struct {
 			struct list_head	list;
 			struct dentry *		dentry;
 			struct inode *		dir_inode;
@@ -399,6 +395,7 @@
 #define CA_AUX_STATEID_LOCKED	0x00000080
 #define CA_AUX_SEQID_MUTATE	0x00000100      /* should handler increase aux. seqid? */
 
+#define CA_RUN_AS_MACHINE       0x00000200 /* inform GSSD to use gss machined creds */
 /*
  * The next four structures define all of the client-side state:
  *   clients, lockowners, file_data, delegations
--- clean/include/linux/nfs4/nfsd4.h	Tue Feb 26 12:00:35 2002
+++ dirty/include/linux/nfs4/nfsd4.h	Mon Feb 25 12:57:00 2002
@@ -60,12 +60,6 @@
 extern const struct gss_oid * const nfsd4_mech_krb5_oid;
 extern const struct gss_oid * const nfsd4_mech_spkm3_oid;
 
-enum rpc_gss_svc_t {
-  RPC_GSS_SVC_NONE = 1,
-  RPC_GSS_SVC_INTEGRITY = 2,
-  RPC_GSS_SVC_PRIVACY = 3
-};
-
 extern int gss_cmp_triples(u32 oid_len, char *oid_data, u32 qop, u32 service);
 
 struct nfs4_export {
--- clean/fs/nfsd4/export.c	Tue Feb 26 12:00:35 2002
+++ dirty/fs/nfsd4/export.c	Mon Feb 25 12:58:11 2002
@@ -52,6 +52,7 @@
 #include <linux/nfs4/nfsd4_xdr.h>
 #include <linux/nfs4/nfsd4.h>
 #include <linux/nfs4/syscall.h>
+#include <linux/sunrpc/auth_gss.h>
 
 #define	EXPORT_HASH_BITS	6
 #define	EXPORT_HASH_SIZE	(1 << EXPORT_HASH_BITS)
--- clean/fs/nfsd4/encode.c	Tue Feb 26 12:00:35 2002
+++ dirty/fs/nfsd4/encode.c	Mon Feb 25 12:58:27 2002
@@ -53,6 +53,7 @@
 #include <linux/nfs4/nfsd4_state.h>
 #include <linux/nfs4/nfsd4_xdr.h>
 #include <linux/nfs4/nfsd4.h>
+#include <linux/sunrpc/auth_gss.h>
 
 #define RDATTR_ERR_LEN		16
 
