Index: enf/src/linux/2.4.17/fs/nfsd/Makefile
diff -u enf/src/linux/2.4.17/fs/nfsd/Makefile:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/Makefile:1.2
--- enf/src/linux/2.4.17/fs/nfsd/Makefile:1.1.1.1	Tue Feb 19 06:20:06 2002
+++ enf/src/linux/2.4.17/fs/nfsd/Makefile	Tue Feb 19 12:38:00 2002
@@ -11,7 +11,7 @@
 
 obj-y :=    nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 	    export.o auth.o lockd.o nfscache.o nfsxdr.o \
-	    stats.o
+	    stats.o enf.o
 
 obj-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
 
Index: enf/src/linux/2.4.17/fs/nfsd/auth.c
diff -u enf/src/linux/2.4.17/fs/nfsd/auth.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/auth.c:1.2
--- enf/src/linux/2.4.17/fs/nfsd/auth.c:1.1.1.1	Tue Feb 19 06:20:16 2002
+++ enf/src/linux/2.4.17/fs/nfsd/auth.c	Tue Feb 19 12:38:00 2002
@@ -9,29 +9,51 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/export.h>
+#include <linux/nfsd/xdr3.h>
+#include <linux/nfsd/enf.h>
 
 #define	CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
 void
 nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 {
 	struct svc_cred	*cred = &rqstp->rq_cred;
-	int		i;
+	int	i;
+	uid_t	newuid;
+	gid_t	newgid;
+
+   	ASSERT(rqstp != NULL);
+	ASSERT(exp != NULL);
 
 	if (rqstp->rq_userset)
 		return;
 
-	if (exp->ex_flags & NFSEXP_ALLSQUASH) {
-		cred->cr_uid = exp->ex_anon_uid;
-		cred->cr_gid = exp->ex_anon_gid;
-		cred->cr_groups[0] = NOGROUP;
-	} else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
-		if (!cred->cr_uid)
+        /* if there is not range mapping on this uid + gid
+         * then preform possible {root,all} squash
+         */
+        newuid = rmap_luid(cred->cr_uid, exp);
+        newgid = rmap_lgid(cred->cr_gid, exp);
+        if(newuid == cred->cr_uid &&
+           newgid == cred->cr_gid) {
+		if (exp->ex_flags & NFSEXP_ALLSQUASH) {
 			cred->cr_uid = exp->ex_anon_uid;
-		if (!cred->cr_gid)
 			cred->cr_gid = exp->ex_anon_gid;
-		for (i = 0; i < NGROUPS; i++)
-			if (!cred->cr_groups[i])
-				cred->cr_groups[i] = exp->ex_anon_gid;
+			cred->cr_groups[0] = NOGROUP;
+		} else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
+			if (!cred->cr_uid)
+				cred->cr_uid = exp->ex_anon_uid;
+			if (!cred->cr_gid)
+				cred->cr_gid = exp->ex_anon_gid;
+			for (i = 0; i < NGROUPS; i++)
+				if (!cred->cr_groups[i])
+					cred->cr_groups[i] = exp->ex_anon_gid;
+		}
+	} else {
+		/* If there is range mapping to be done, do it. 
+		 * Here we are doing remote to local range mapping.
+		 */
+		cred->cr_uid = newuid;
+		cred->cr_gid = newgid;
 	}
 
 	if (cred->cr_uid != (uid_t) -1)
@@ -46,7 +68,7 @@
 		gid_t group = cred->cr_groups[i];
 		if (group == (gid_t) NOGROUP)
 			break;
-		current->groups[i] = group;
+		current->groups[i] = rmap_lgid(group, exp);
 	}
 	current->ngroups = i;
 
Index: enf/src/linux/2.4.17/fs/nfsd/enf.c
diff -u /dev/null enf/src/linux/2.4.17/fs/nfsd/enf.c:1.3
--- /dev/null	Tue Mar 19 02:10:52 2002
+++ enf/src/linux/2.4.17/fs/nfsd/enf.c	Mon Mar 11 22:20:12 2002
@@ -0,0 +1,766 @@
+/* enf.c
+ * 
+ * Enhanced NFS Features (ENF) 
+ *
+ * supported features
+ *   uid/gid range mapping
+ *   file cloaking
+ * 
+ * Sun Mar  4 07:37:32 2001
+ *   Joseph Spadavecchia [JES] <joseph@cs.sunysb.edu>
+ *   Nenad Dedic <nenad@cs.bu.edu>
+ */
+
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/in.h>
+#include <linux/types.h>
+
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/nfsfh.h>
+#include <linux/nfsd/auth.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/nfsd/export.h>
+#include <linux/lockd/bind.h>
+#include <linux/nfsd/xdr3.h>
+#include <linux/nfsd/enf.h>
+
+extern struct list_head g_enfdl;  /* global definition lists */
+
+int enf_add(struct nfsctl_enf *data)
+{
+	struct svc_export *exp;
+	struct list_head  *defl, *index;
+	struct enf_dl	  *target;
+	struct enf_rmap	  *newrmap;
+	struct enf_clist  *newclist;
+	unsigned char type;
+	char *sz_id, *sz_client, *sz_path;
+	int err, i, found, isuid;
+	
+	ASSERT(data);
+
+	target = NULL;
+	type = data->ne_type;
+	switch(type) {
+	case ENF_TRMAP:
+	case ENF_TCLIST:
+		break;
+	default:
+		err = -EINVAL;
+		goto out_err;
+	}
+
+	err = 0;
+	defl = &(g_enfdl);
+	sz_id = data->ne_id;
+	sz_client = data->ne_client;
+	sz_path = data->ne_path;
+	isuid = data->ne_uid;
+
+        /* Try to lock the export table for update */
+        if ((err = exp_writelock()) < 0) {
+                goto out_err;
+	}
+
+	if (!(exp = enf_find_exp(sz_client, sz_path))) {
+		err = -ENOENT;
+		goto out_unlock;
+	}
+
+	/* lookup sz_id global entry in def. lists 
+	 * sz_id is ONLY needed when adding new range 
+	 * mapping or file cloaking informaiton
+         * it should be the path and hostname (FQDN or not)
+	 * as it apprears in the /etc/exports file
+         * this allows us to save memory 
+	 */
+	found = 0;
+	list_for_each(index, defl) {
+		target = list_entry(index, struct enf_dl, ed_list);
+
+        	if(strncmp(target->ed_id, sz_id,
+                		NFSCLNT_IDMAX + NFS_MAXPATHLEN) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	/* if there is not a global entry
+         * create one
+	 */ 
+	if (!found) {
+		target = (struct enf_dl*)kmalloc(sizeof(struct enf_dl),
+						       GFP_KERNEL);
+		if (target == NULL) {
+			err = -ENOMEM;
+			goto out_unlock;
+		}
+		strncpy(target->ed_id, sz_id,
+			NFSCLNT_IDMAX + NFS_MAXPATHLEN);
+		
+		for(i = 0; i < ENF_MAXTYPE; i++) {
+			target->ed_refcnt[i] = 0;
+			INIT_LIST_HEAD(&(target->ed_opaque[i][ENF_TUID]));
+			INIT_LIST_HEAD(&(target->ed_opaque[i][ENF_TGID]));
+		}
+		/* add this def to the global definition lists */
+		list_add(&(target->ed_list), defl);
+	}
+
+	switch(type) {
+	case ENF_TRMAP:
+		found = 0;
+		list_for_each(index, &(target->ed_opaque[type][!isuid])) {
+			newrmap = list_entry(index, struct enf_rmap, er_list);
+			
+			if(isuid && newrmap->u_lo.uid == data->u_lo.uid &&
+			   newrmap->u_hi.uid == data->u_hi.uid &&
+			   newrmap->u_mapto.uid == data->u_mapto.uid &&
+			   newrmap->er_map == data->ne_map) {
+				found = 1;
+				break;
+			} else if(!isuid && newrmap->u_lo.gid == data->u_lo.gid &&
+                           newrmap->u_hi.gid == data->u_hi.gid &&
+                           newrmap->u_mapto.gid == data->u_mapto.gid &&
+                           newrmap->er_map == data->ne_map) {
+				found = 1;
+                                break;
+                        }
+		}
+
+		if(found) {
+			goto out;
+		}
+
+		if (!(newrmap = 
+			(struct enf_rmap *)kmalloc(sizeof(struct enf_rmap), GFP_KERNEL))) {	
+			err = -ENOMEM;
+			goto out_unlock;
+		}
+
+		list_add(&(newrmap->er_list), &(target->ed_opaque[ENF_TRMAP][!isuid]));
+	
+		if(isuid) {	
+			newrmap->u_lo.uid = data->u_lo.uid;
+			newrmap->u_hi.uid = data->u_hi.uid;
+			newrmap->u_mapto.uid = data->u_mapto.uid;
+		} else {
+			newrmap->u_lo.gid = data->u_lo.gid;
+			newrmap->u_hi.gid = data->u_hi.gid;
+			newrmap->u_mapto.gid = data->u_mapto.gid;
+		}
+
+		newrmap->er_map = data->ne_map;
+		break;
+	case ENF_TCLIST:
+		ENF_MASK2MODE(data->ne_mask);
+		found = 0;
+		list_for_each(index, &(target->ed_opaque[type][!isuid])) {
+			newclist = list_entry(index, struct enf_clist, ec_list);
+
+			if(isuid && newclist->u_lo.uid == data->u_lo.uid &&
+			   newclist->u_hi.uid == data->u_hi.uid &&
+			   newclist->ec_mask == data->ne_mask) {
+				found = 1;
+				break;
+			} else if(!isuid && newclist->u_lo.gid == data->u_lo.gid &&
+                           newclist->u_hi.gid == data->u_hi.gid &&
+                           newclist->ec_mask == data->ne_mask) {
+				found = 1;
+                                break;
+                        }
+		}
+		
+		if(found) {
+			goto out;
+		}
+
+		if (!(newclist = 
+			(struct enf_clist *)kmalloc(sizeof(struct enf_clist), GFP_KERNEL))) {	
+			err = -ENOMEM;	
+			goto out_unlock;
+		}
+			
+			list_add(&(newclist->ec_list), &(target->ed_opaque[ENF_TCLIST][!isuid]));
+
+		if(isuid) {	
+			newclist->u_lo.uid = data->u_lo.uid;
+			newclist->u_hi.uid = data->u_hi.uid;
+		} else {
+			newclist->u_lo.gid = data->u_lo.gid;
+			newclist->u_hi.gid = data->u_hi.gid;
+		}
+
+		newclist->ec_mask = data->ne_mask;
+
+		break;
+	}
+
+out:
+	/* regardless inc the refcnt */
+	if (!(exp->ex_opaque[type][ENF_TUID] || exp->ex_opaque[ENF_TRMAP][ENF_TGID])) {
+		target->ed_refcnt[type]++;
+	}
+
+	exp->ex_opaque[type][!isuid] = &(target->ed_opaque[type][!isuid]);
+
+out_unlock:
+        exp_unlock();
+out_err: 
+	return err;
+}
+
+int enf_delete(struct nfsctl_enf *data)
+{
+	struct svc_export   *exp;
+	struct svc_client   *clp;
+	struct enf_rmap     *targetrmap = NULL;
+	struct enf_clist    *targetclist = NULL; 
+	struct list_head    *defl, *index, *index2;
+	struct enf_dl	    *target = NULL;
+	unsigned short  isuid;
+	unsigned char	type;
+	char *sz_client, *sz_path;
+	int err, i, found;
+
+	ASSERT(data);
+
+	type = data->ne_type;
+	switch(type) {
+	case ENF_TRMAP:
+	case ENF_TCLIST:
+		break;
+	default:
+		err = -EINVAL;
+		goto out_err;
+	}
+
+	err = 0;
+	defl = &(g_enfdl);
+	sz_client = data->ne_client;
+	sz_path = data->ne_path;
+	isuid = data->ne_uid;
+
+        /* Try to lock the export table for update */
+        if ((err = exp_writelock()) < 0) {
+                goto out_err;
+	}
+
+	if(!(exp = enf_find_exp(sz_client, sz_path))) {
+		err = -ENOENT;
+		goto out_unlock;
+	}
+
+	/* check def. list for exp */
+	found = 0;
+	list_for_each(index, defl) {
+		target = list_entry(index, struct enf_dl, ed_list);
+
+		if(exp->ex_opaque[type][!isuid] == &(target->ed_opaque[type][!isuid]) || 
+			exp->ex_opaque[type][!isuid] == &(target->ed_opaque[type][!isuid])) {
+			found = 1;
+			break;
+		}
+	}
+
+	if(!found) {
+		goto out_unlock;
+	}
+
+	switch(type) {
+	case ENF_TRMAP:
+		found = 0;
+		list_for_each(index2, &(target->ed_opaque[type][!isuid])) {
+			targetrmap = list_entry(index2, struct enf_rmap, er_list);
+			
+			if(isuid && targetrmap->u_lo.uid == data->u_lo.uid &&
+			   targetrmap->u_hi.uid == data->u_hi.uid &&
+			   targetrmap->u_mapto.uid == data->u_mapto.uid &&
+			   targetrmap->er_map == data->ne_map) {
+				found = 1;
+				break;
+			} else if(!isuid && targetrmap->u_lo.gid == data->u_lo.gid &&
+                           targetrmap->u_hi.gid == data->u_hi.gid &&
+                           targetrmap->u_mapto.gid == data->u_mapto.gid &&
+                           targetrmap->er_map == data->ne_map) {
+				found = 1;
+                                break;
+                        }
+		}
+	
+		if(!found) {
+			err = -ENOENT;
+			goto out_unlock;
+		}
+		list_del(index2);
+		kfree(targetrmap);
+		break;
+	case ENF_TCLIST:
+		found = 0;
+		list_for_each(index2, &(target->ed_opaque[type][!isuid])) {
+			targetclist = list_entry(index2, struct enf_clist, ec_list);
+			ENF_MASK2MODE(data->ne_mask);
+			if(isuid && targetclist->u_lo.uid == data->u_lo.uid &&
+			   targetclist->u_hi.uid == data->u_hi.uid &&
+			   targetclist->ec_mask == data->ne_mask) {
+				found = 1;
+				break;
+			} else if(!isuid && targetclist->u_lo.gid == data->u_lo.gid &&
+                           targetclist->u_hi.gid == data->u_hi.gid &&
+                           targetclist->ec_mask == data->ne_mask) {
+				found = 1;
+                                break;
+                        }
+		}
+	
+		if(!found) {
+			err = -ENOENT;
+			goto out_unlock;
+		}
+		list_del(index2);
+		kfree(targetclist);
+		break;
+	}
+
+	if(list_empty(&(target->ed_opaque[type][!isuid]))) {
+		exp->ex_opaque[type][!isuid] = NULL;
+		target->ed_refcnt[type]--;
+
+		switch(type) {
+		case ENF_TRMAP:
+			if(isuid) {
+				ENF_HASH_INIT(exp->ex_ruid);
+				ENF_HASH_INIT(exp->ex_luid);
+			} else {
+				ENF_HASH_INIT(exp->ex_rgid);
+				ENF_HASH_INIT(exp->ex_rgid);
+			}
+			break;
+		case ENF_TCLIST:
+			if(isuid) {
+				ENF_HASH_INIT(exp->ex_cuid);
+			} else {
+				ENF_HASH_INIT(exp->ex_cgid);
+			}
+			break;
+		}
+		/* search for other exports pointing to this def. list entry
+		 * and nullify their def. list pointers + adjust refcnt 
+		 * on the def. list entry 
+		 */
+		for (clp = get_clients(); clp; clp = clp->cl_next) {
+			for (i = 0; i < NFSCLNT_EXPMAX; i++) {
+				if ((exp = (clp->cl_export)[i])) {
+					do {
+						if (exp->ex_opaque[type][!isuid]
+							 == &(target->ed_opaque[type][!isuid])) {
+							target->ed_refcnt[type]--;
+							exp->ex_opaque[type][!isuid] = NULL;
+							switch(type) {
+							case ENF_TRMAP:
+								if(isuid) {
+									ENF_HASH_INIT(exp->ex_ruid);
+									ENF_HASH_INIT(exp->ex_luid);
+								} else {
+									ENF_HASH_INIT(exp->ex_rgid);
+									ENF_HASH_INIT(exp->ex_rgid);
+								}
+								break;
+							case ENF_TCLIST:
+								if(isuid) {
+									ENF_HASH_INIT(exp->ex_cuid);
+								} else {
+									ENF_HASH_INIT(exp->ex_cgid);
+								}
+								break;
+							}
+						}
+					} while ((exp = exp->ex_next));
+				}
+			}
+		}
+
+		if (!target->ed_refcnt[ENF_TRMAP] && !target->ed_refcnt[ENF_TCLIST]) {
+			/* remove definition list entry */
+			list_del(&(target->ed_list));
+			kfree(target);
+		}
+	}
+out_unlock:
+	exp_unlock();
+out_err: 
+	return err;
+}
+
+int enf_flush(struct nfsctl_enf *data)
+{
+	struct list_head    *defl, *index, *index2;
+	struct enf_rmap	    *rmap;
+	struct enf_clist    *clist;
+	struct enf_dl	    *target;
+	struct svc_export   *exp;
+	int err, found;
+	unsigned char	type;
+	char *sz_path, *sz_client;
+
+	ASSERT(data);
+
+	err = 0;
+	target = NULL;
+	type = data->ne_type;
+	switch(type) {
+	case ENF_TRMAP:
+	case ENF_TCLIST:
+		break;
+	default:
+		err = -EINVAL;
+		goto out_err;
+	}
+
+	defl = &(g_enfdl);
+	sz_client = data->ne_client;
+	sz_path = data->ne_path;
+
+        /* Try to lock the export table for update */
+        if ((err = exp_writelock()) < 0) {
+                goto out_err;
+	}
+
+	/* find the export */
+	if (!(exp = enf_find_exp(sz_client, sz_path))) {
+		err = -ENOENT;
+		goto out_unlock;
+	}
+
+	/* find the corresponding definition list entry */
+	found = 0;
+	list_for_each(index, defl) {
+		target = list_entry(index, struct enf_dl, ed_list);
+		if(exp->ex_opaque[type][ENF_TUID] == &(target->ed_opaque[type][ENF_TUID]) || 
+			exp->ex_opaque[type][ENF_TGID] == &(target->ed_opaque[type][ENF_TGID])) {
+				found = 1;
+				break;
+		}
+	}
+
+	if(!found) {
+		goto out_unlock;
+	}
+
+	exp->ex_opaque[type][ENF_TUID] = NULL;
+	exp->ex_opaque[type][ENF_TGID] = NULL;
+
+	switch(type) {
+	case ENF_TRMAP:
+		ENF_HASH_INIT(exp->ex_ruid);
+		ENF_HASH_INIT(exp->ex_rgid);
+		ENF_HASH_INIT(exp->ex_luid);
+		ENF_HASH_INIT(exp->ex_lgid);
+		break;
+	case ENF_TCLIST:
+		ENF_HASH_INIT(exp->ex_cuid);
+		ENF_HASH_INIT(exp->ex_cgid);
+		break;
+	}
+
+	target->ed_refcnt[type]--;
+	if (!(target->ed_refcnt[type])) {
+		switch(type) {
+		case ENF_TRMAP:
+			/* free uid list */
+			list_for_each(index2, &(target->ed_opaque[ENF_TRMAP][ENF_TUID])) {
+				rmap = list_entry(index2, struct enf_rmap, er_list);
+				list_del(&(rmap->er_list));
+				kfree(rmap);
+			}
+				
+			/* free gid list */
+			list_for_each(index2, &(target->ed_opaque[ENF_TRMAP][ENF_TGID])) {
+				rmap = list_entry(index2, struct enf_rmap, er_list);
+				list_del(&(rmap->er_list));
+				kfree(rmap);
+			}
+			break;
+		case ENF_TCLIST:
+			/* free uid list */
+			list_for_each(index2, &(target->ed_opaque[ENF_TCLIST][ENF_TUID])) {
+				clist = list_entry(index2, struct enf_clist, ec_list);
+				list_del(&(clist->ec_list));
+				kfree(clist);
+			}
+				
+			/* free gid list */
+			list_for_each(index2, &(target->ed_opaque[ENF_TCLIST][ENF_TGID])) {
+				clist = list_entry(index2, struct enf_clist, ec_list);
+				list_del(&(clist->ec_list));
+				kfree(clist);
+			}
+			break;
+		}
+
+		if(!target->ed_refcnt[ENF_TRMAP] && !target->ed_refcnt[ENF_TCLIST]) {
+			/* remove definition list entry */
+			list_del(&(target->ed_list));
+			kfree(target);
+		}
+	}
+
+out_unlock:
+	exp_unlock();
+out_err:
+	return err;
+}
+
+/**
+ * Returns the export with client @cl_name and path @path.
+ * IN:
+ * 	@cl_name: client name
+ *	@path: export path
+ * OUT:
+ * 	if found the svc_export else NULL
+ *
+ * (This function assumes locking before invocation.) 
+ */
+struct svc_export *enf_find_exp(char *cl_name, char *path)
+{
+	struct svc_client *clp;
+	struct svc_export *exp;
+	int i;
+
+	ASSERT(cl_name);
+	ASSERT(path);
+
+	/* TODO: what about parents */ 
+	for (clp = get_clients(); clp; clp = clp->cl_next) {
+		if (strcmp(clp->cl_ident, cl_name) == 0) {
+			for (i = 0; i < NFSCLNT_EXPMAX; i++) {
+				if ((exp = (clp->cl_export)[i])) {
+					do {
+						if (strcmp(exp->ex_path, path) == 0) {
+							/* found */
+							goto out;
+						}
+					} while ((exp = exp->ex_next));
+				}
+			}
+		}
+	}
+	/* haven't found */
+	exp = NULL;
+out:
+	return exp;
+}
+
+/**
+ * Map a local uid to a remote uid.
+ * (reverse mapping)
+ * IN:
+ * 	@svc_rqst: structure 'rqstp' containing 
+ *                 _the_ svc_fh in '.rq_resp'
+ * 	@id: local uid 
+ * OUT:
+ * 	if there exists a reverse range mapping
+ *      for 'id' the remote uid is calculated
+ *      from it and returned
+ * 	else then 'id' is returned unchanged
+ *
+ * (This function assumes locking before invocation.) 
+ */
+uid_t rmap_ruid(struct svc_rqst *rqstp, uid_t id)
+{
+	struct svc_export *exp;
+	struct enf_rmap   *map;
+	struct list_head  *index;
+	uid_t newid, tmpid;
+	int   i_hv;
+
+	ASSERT(rqstp != NULL);
+
+	newid = id;
+	exp = nfs3svc_rqst2exp(rqstp);
+	if(!exp) {
+		printk(KERN_DEBUG "RMAP: null export - (this should never happen)\n");
+		/* return old id */
+		goto out;
+	}
+
+	if (!(exp->ex_opaque[ENF_TRMAP][ENF_TUID])) {
+		goto out;
+	}
+   
+	i_hv = ENF_HASH_FUNCTION(id);
+	if (exp->ex_ruid[i_hv][ENF_HSRC] != id) { 
+		list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TUID]) {
+			map = list_entry(index, struct enf_rmap, er_list);
+			if (map->er_map) {
+				/* range map -- we do reverse mapping only when
+				 * range mapping is in question
+				 */
+				/* for squashing, reverse maps make no sense */
+				tmpid = id - map->u_mapto.uid + map->u_lo.uid;
+				if ((map->u_lo.uid <= tmpid) && (tmpid <= map->u_hi.uid) ) {
+					newid = tmpid;
+					exp->ex_ruid[i_hv][ENF_HSRC] = id;
+					exp->ex_ruid[i_hv][ENF_HDST] = newid;
+					break;
+				}
+			}
+		}
+	} else {
+		newid = exp->ex_ruid[i_hv][ENF_HDST];
+	}
+out:
+	return newid;
+}
+
+/* (This function assumes locking before invocation.) */ 
+gid_t rmap_rgid(struct svc_rqst *rqstp, gid_t id)
+{
+	struct svc_export *exp;
+	struct enf_rmap   *map;
+	struct list_head  *index;
+	gid_t newid, tmpid;
+	int   i_hv;
+	
+	ASSERT(rqstp != NULL);
+
+	newid = id;
+	exp = nfs3svc_rqst2exp(rqstp);
+	if(!exp) {
+		/* return old id */
+		goto out;
+	}
+
+	if (!(exp->ex_opaque[ENF_TRMAP][ENF_TGID])) {
+		goto out;
+	}
+      
+	i_hv = ENF_HASH_FUNCTION(id);
+	
+	if(exp->ex_rgid[i_hv][ENF_HSRC] != id) {
+		list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TGID]) {
+			map = list_entry(index, struct enf_rmap, er_list);
+
+			if (map->er_map) {
+				/* range map -- we do reverse mapping only when
+				 * range mapping is in question
+				 */
+		  
+				/* for squashing, reverse maps make no sense */
+				tmpid = id - map->u_mapto.gid + map->u_lo.gid;
+				if ((map->u_lo.gid <= tmpid) && (tmpid <= map->u_hi.gid)) {
+					newid = tmpid;
+					exp->ex_rgid[i_hv][ENF_HSRC] = id;
+					exp->ex_rgid[i_hv][ENF_HDST] = newid;
+					break;
+				}
+			}
+		}
+	} else {
+		newid = exp->ex_rgid[i_hv][ENF_HDST];
+	}
+out:
+	return newid;
+}
+
+/**
+ * Map a remote uid to a local uid.
+ * IN:
+ * 	@svc_rqst: structure 'rqstp' containing 
+ *                 _the_ svc_fh in '.rq_resp'
+ * 	@ruid: remote uid 
+ * OUT:
+ * 	if there exists a range mapping
+ *      for 'ruid' the local uid is calculated
+ *      and returned else then 'ruid' is returned
+ *
+ * (This function assumes locking before invocation.) 
+ */
+uid_t rmap_luid(uid_t ruid, struct svc_export *exp)
+{
+	struct enf_rmap *map = NULL;
+	struct list_head *index;
+	uid_t newid;
+	int i_hv;
+
+	ASSERT(exp != NULL);
+
+	newid = ruid;
+	/* get credentials */
+	if (!(exp->ex_opaque[ENF_TRMAP][ENF_TUID])) {
+		goto out;
+	}
+
+	i_hv = ENF_HASH_FUNCTION(ruid);
+	
+	if (exp->ex_luid[i_hv][ENF_HSRC] != ruid) { 
+		list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TUID]) {
+			map = list_entry(index, struct enf_rmap, er_list);
+                        if ((map->u_lo.uid <= ruid) && (ruid <= map->u_hi.uid)) {
+                                /* map this uid */
+                                if (map->er_map) {
+                                        /* range map */
+                                        newid = map->u_mapto.uid - map->u_lo.uid + ruid;
+                                } else {
+                                        /* squash */
+                                        newid = map->u_mapto.uid;
+                                }
+
+                                exp->ex_luid[i_hv][ENF_HSRC] = ruid;
+                                exp->ex_luid[i_hv][ENF_HDST] = newid;
+
+                                break;
+                        }
+
+		}
+	} else {
+		newid = exp->ex_luid[i_hv][ENF_HDST];
+	}
+out:
+	return newid;
+}
+
+uid_t rmap_lgid(uid_t rgid, struct svc_export *exp)
+{
+	struct enf_rmap  *map;
+	struct list_head *index;
+	uid_t newid;
+	int i_hv;
+
+	ASSERT(exp != NULL);
+	
+	newid = rgid;
+	/* get credentials */
+	if (!(exp->ex_opaque[ENF_TRMAP][ENF_TGID])) {
+		goto out;
+	}
+
+	i_hv = ENF_HASH_FUNCTION(rgid);
+
+	if (exp->ex_lgid[i_hv][ENF_HSRC] != rgid) {
+		list_for_each(index, exp->ex_opaque[ENF_TRMAP][ENF_TGID]) {
+			map = list_entry(index, struct enf_rmap, er_list);
+			if ((map->u_lo.gid <= rgid) && (rgid <= map->u_hi.gid)) {
+				/* map this gid */
+				if (map->er_map) {
+					/* range map */
+					newid = map->u_mapto.gid - map->u_lo.gid + rgid;
+				} else {
+					/* squash */
+					newid = map->u_mapto.gid;
+				}
+
+				exp->ex_lgid[i_hv][ENF_HSRC] = rgid;
+				exp->ex_lgid[i_hv][ENF_HDST] = newid;
+
+				break;
+			}
+		}
+	} else {
+		newid = exp->ex_lgid[i_hv][ENF_HDST];
+	}
+out:
+	return newid;
+}
Index: enf/src/linux/2.4.17/fs/nfsd/export.c
diff -u enf/src/linux/2.4.17/fs/nfsd/export.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/export.c:1.5
--- enf/src/linux/2.4.17/fs/nfsd/export.c:1.1.1.1	Tue Feb 19 06:20:06 2002
+++ enf/src/linux/2.4.17/fs/nfsd/export.c	Mon Mar 11 22:20:12 2002
@@ -1,4 +1,3 @@
-#define MSNFS	/* HACK HACK */
 /*
  * linux/fs/nfsd/export.c
  *
@@ -25,6 +24,11 @@
 #include <linux/nfsd/syscall.h>
 #include <linux/lockd/bind.h>
 
+#include <linux/nfsd/enf.h>
+#include <linux/nfsd/auth.h>
+#include <linux/nfsd/xdr3.h>
+
+
 #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
 #define NFSD_PARANOIA 1
 
@@ -65,6 +69,16 @@
 static int			hash_count;
 static DECLARE_WAIT_QUEUE_HEAD(	hash_wait );
 
+/* ENF (Enhanced NFS Featrues)
+ * global definition list 
+ */
+LIST_HEAD(g_enfdl);
+
+struct svc_client *
+get_clients()
+{
+	return clients;
+}
 
 /*
  * Find a client's export for a device.
@@ -184,6 +198,7 @@
 		exp->ex_flags    = nxp->ex_flags;
 		exp->ex_anon_uid = nxp->ex_anon_uid;
 		exp->ex_anon_gid = nxp->ex_anon_gid;
+
 		err = 0;
 		goto out_unlock;
 	}
@@ -245,6 +260,11 @@
 	exp->ex_anon_uid = nxp->ex_anon_uid;
 	exp->ex_anon_gid = nxp->ex_anon_gid;
 
+        exp->ex_opaque[ENF_TRMAP][ENF_TUID] = NULL;
+        exp->ex_opaque[ENF_TRMAP][ENF_TGID] = NULL;
+        exp->ex_opaque[ENF_TCLIST][ENF_TUID] = NULL;
+        exp->ex_opaque[ENF_TCLIST][ENF_TGID] = NULL;
+
 	/* Update parent pointers of all exports */
 	if (parent) {
 		for (i = 0; i < NFSCLNT_EXPMAX; i++) {
@@ -386,7 +406,7 @@
 	struct svc_fh		fh;
 	int			err;
 
-	err = -EPERM;
+   err = -EPERM;
 	if (path) {
 		if (path_init(path, LOOKUP_POSITIVE, &nd) &&
 		    path_walk(path, &nd)) {
@@ -552,7 +572,6 @@
 	{ NFSEXP_ALLSQUASH, {"all_squash", ""}},
 	{ NFSEXP_ASYNC, {"async", "sync"}},
 	{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
-	{ NFSEXP_UIDMAP, {"uidmap", ""}},
 	{ NFSEXP_KERBEROS, { "kerberos", ""}},
 	{ NFSEXP_SUNSECURE, { "sunsecure", ""}},
 	{ NFSEXP_CROSSMNT, {"nohide", ""}},
@@ -620,6 +639,7 @@
 {
 	struct svc_clnthash	**hp, **head, *tmp;
 	struct svc_client	*clp;
+
 	svc_export *exp;
 	off_t	pos = 0;
         off_t	begin = 0;
@@ -656,19 +676,23 @@
 									htonl(addr.s_addr) >>  8 & 0xff,
 									htonl(addr.s_addr) >>  0 & 0xff);
 							if (tmp->h_client != clp)
+							{
+			
 							  len += sprintf(buffer+len, ")");
+							}
 							break;
 						}
 					}
 				}
+
 				exp = exp->ex_next;
 
-				buffer[len++]='\n';
+				buffer[len++] = '\n';
 
-				pos=begin+len;
-				if(pos<offset) {
-					len=0;
-					begin=pos;
+				pos = begin + len;
+				if(pos < offset) {
+					len = 0;
+					begin = pos;
 				}
 				if (pos > offset + length)
 					goto done;
@@ -683,6 +707,48 @@
 	len -= (offset - begin);
 	if ( len > length )
 		len = length;
+
+	return len;
+}
+
+int
+exp_procfs_debug(char *buffer, char **start, off_t offset,
+                             int length, int *eof, void *data)
+{
+	struct list_head *index, *index2;
+	struct enf_dl	 *defl;
+	int len = 0;
+
+	int ur_cnt = 0;
+	int gr_cnt = 0;
+	int uc_cnt = 0;
+	int gc_cnt = 0;
+
+	list_for_each(index, &(g_enfdl)) {
+		defl = list_entry(index, struct enf_dl, ed_list); 
+
+		list_for_each(index2, &(defl->ed_opaque[ENF_TRMAP][ENF_TUID])) {
+			ur_cnt++;
+		}
+		
+		list_for_each(index2, &(defl->ed_opaque[ENF_TRMAP][ENF_TGID])) {
+			gr_cnt++;	
+		}
+
+		list_for_each(index2, &(defl->ed_opaque[ENF_TCLIST][ENF_TUID])) {
+			uc_cnt++;
+		}
+
+		list_for_each(index2, &(defl->ed_opaque[ENF_TCLIST][ENF_TGID])) {
+			gc_cnt++;
+		}
+	}
+
+	len += sprintf(buffer + len, "%d uid rmap(s) installed\n", ur_cnt);
+	len += sprintf(buffer + len, "%d gid rmap(s) installed\n", gr_cnt);
+	len += sprintf(buffer + len, "%d uid clist(s) installed\n", uc_cnt);
+	len += sprintf(buffer + len, "%d gid clist(s) installed\n", gc_cnt);
+
 	return len;
 }
 
Index: enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c
diff -u enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c:1.3
--- enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c:1.1.1.1	Tue Feb 19 06:20:16 2002
+++ enf/src/linux/2.4.17/fs/nfsd/nfs3xdr.c	Mon Mar 11 22:20:12 2002
@@ -14,6 +14,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr3.h>
+#include <linux/nfsd/enf.h>
+#include <linux/nfsd/export.h>
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
@@ -157,12 +159,14 @@
 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
 {
 	struct inode	*inode = dentry->d_inode;
+	static unsigned long    lasttime;
+	struct svc_export  *expp;
 
 	*p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
 	*p++ = htonl((u32) inode->i_mode);
 	*p++ = htonl((u32) inode->i_nlink);
-	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
-	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
+	*p++ = htonl((u32) rmap_ruid(rqstp, inode->i_uid));
+	*p++ = htonl((u32) rmap_rgid(rqstp, inode->i_gid));
 	if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
 		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 	} else {
@@ -178,7 +182,24 @@
 	p = xdr_encode_hyper(p, (u64) inode->i_dev);
 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, inode->i_atime);
-	p = encode_time3(p, lease_get_mtime(inode));
+
+	/* make readdir persist 
+	 * THIS IS NECESSARY FOR FILE CLOAKING
+         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	 */
+        expp = nfs3svc_rqst2exp(rqstp);
+        if(expp && (expp->ex_opaque[ENF_TCLIST][ENF_TUID] || expp->ex_opaque[ENF_TCLIST][ENF_TGID])
+                && inode->i_mode & S_IFDIR && (expp->ex_flags & NFSEXP_NOCLIENTCACHE)) {
+		if(CURRENT_TIME <= lasttime) {
+			lasttime++;
+		} else {
+			lasttime = CURRENT_TIME;
+		}
+		p = encode_time3(p, lasttime);
+	} else {
+		p = encode_time3(p, lease_get_mtime(inode));
+	}
+
 	p = encode_time3(p, inode->i_ctime);
 
 	return p;
@@ -195,8 +216,8 @@
 	*p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
 	*p++ = htonl((u32) fhp->fh_post_mode);
 	*p++ = htonl((u32) fhp->fh_post_nlink);
-	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
-	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
+	*p++ = htonl((u32) rmap_ruid(rqstp, fhp->fh_post_uid));
+	*p++ = htonl((u32) rmap_rgid(rqstp, fhp->fh_post_gid));
 	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
 		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 	} else {
@@ -654,8 +675,32 @@
 encode_entry(struct readdir_cd *cd, const char *name,
 	     int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
 {
-	u32		*p = cd->buffer;
-	int		buflen, slen, elen;
+	u32	*p = cd->buffer;
+	int	buflen=0, slen, elen;
+	struct dentry		*dentry;
+	struct svc_export	*exp = NULL;
+
+	/* file cloaking */
+	if(cd && cd->dirfh) { 
+		exp = cd->dirfh->fh_export;
+
+		dentry = lookup_one_len(name, cd->dirfh->fh_dentry, namlen);
+		if(!IS_ERR(dentry) && dentry) {
+			/* check for file cloaking */
+			int iscl = 0;
+
+			if (exp) {
+				iscl = clist_iscloaked(exp, dentry->d_inode);
+			}
+
+			dput(dentry);
+
+			if (iscl) {
+				/* perform file cloaking */
+				return 0;
+			}
+		}
+	}
 
 	if (cd->offset)
 		xdr_encode_hyper(cd->offset, (u64) offset);
@@ -664,11 +709,6 @@
 	 * set the last offset entry. */
 	if (name == 0)
 		return 0;
-
-	/*
-	dprintk("encode_entry(%.*s @%ld%s)\n",
-		namlen, name, (long) offset, plus? " plus" : "");
-	 */
 
 	/* truncate filename if too long */
 	if (namlen > NFS3_MAXNAMLEN)
Index: enf/src/linux/2.4.17/fs/nfsd/nfsctl.c
diff -u enf/src/linux/2.4.17/fs/nfsd/nfsctl.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfsctl.c:1.2
--- enf/src/linux/2.4.17/fs/nfsd/nfsctl.c:1.1.1.1	Tue Feb 19 06:20:22 2002
+++ enf/src/linux/2.4.17/fs/nfsd/nfsctl.c	Tue Feb 19 12:38:00 2002
@@ -28,6 +28,7 @@
 #include <linux/nfsd/xdr.h>
 #include <linux/nfsd/syscall.h>
 
+#include <linux/nfsd/enf.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
@@ -40,20 +41,22 @@
 static int	nfsctl_getfh(struct nfsctl_fhparm *, __u8 *);
 static int	nfsctl_getfd(struct nfsctl_fdparm *, __u8 *);
 static int	nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
-#ifdef notyet
-static int	nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
-#endif
+
+static int	nfsctl_enf(struct nfsctl_enf *data);
 
 static int	initialized;
 
 int exp_procfs_exports(char *buffer, char **start, off_t offset,
                              int length, int *eof, void *data);
+int exp_procfs_debug(char *buffer, char **start, off_t offset,
+                             int length, int *eof, void *data);
 
 void proc_export_init(void)
 {
 	if (!proc_mkdir("fs/nfs", 0))
 		return;
 	create_proc_read_entry("fs/nfs/exports", 0, 0, exp_procfs_exports,NULL);
+	create_proc_read_entry("fs/nfs/debug", 0, 0, exp_procfs_debug, NULL);
 }
 
 
@@ -101,13 +104,32 @@
 	return exp_unexport(data);
 }
 
-#ifdef notyet
 static inline int
-nfsctl_ugidupdate(nfs_ugidmap *data)
+nfsctl_enf(struct nfsctl_enf *data)
 {
-	return -EINVAL;
+	int i_ret;
+	unsigned short func;
+
+	func = data->ne_func;
+
+	switch(func) {
+	case ENF_ADD:
+		i_ret = enf_add(data);
+		break;
+	case ENF_DELETE:
+		i_ret = enf_delete(data);
+		break;
+	case ENF_FLUSH:
+		i_ret = enf_flush(data);
+		break;
+	default:
+		i_ret = -EINVAL;
+		goto out;
+
+	}
+out:   
+	return i_ret;
 }
-#endif
 
 static inline int
 nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
@@ -208,7 +230,7 @@
 	/* NFSCTL_DELCLIENT  */ { sizeof(struct nfsctl_client), 0},
 	/* NFSCTL_EXPORT     */ { sizeof(struct nfsctl_export), 0},
 	/* NFSCTL_UNEXPORT   */ { sizeof(struct nfsctl_export), 0},
-	/* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0},
+	/* NFSCTL_ENF        */ { sizeof(struct nfsctl_enf), 0},
 	/* NFSCTL_GETFH      */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE},
 	/* NFSCTL_GETFD      */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE},
 	/* NFSCTL_GETFS      */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)},
@@ -272,11 +294,9 @@
 	case NFSCTL_UNEXPORT:
 		err = nfsctl_unexport(&arg->ca_export);
 		break;
-#ifdef notyet
-	case NFSCTL_UGIDUPDATE:
-		err = nfsctl_ugidupdate(&arg->ca_umap);
+	case NFSCTL_ENF:
+		err = nfsctl_enf(&arg->ca_enf);
 		break;
-#endif
 	case NFSCTL_GETFH:
 		err = nfsctl_getfh(&arg->ca_getfh, res->cr_getfh);
 		break;
@@ -336,6 +356,7 @@
 	nfsd_export_shutdown();
 	nfsd_cache_shutdown();
 	remove_proc_entry("fs/nfs/exports", NULL);
+	remove_proc_entry("fs/nfs/debug", NULL);
 	remove_proc_entry("fs/nfs", NULL);
 	nfsd_stat_shutdown();
 	nfsd_lockd_shutdown();
Index: enf/src/linux/2.4.17/fs/nfsd/nfsfh.c
diff -u enf/src/linux/2.4.17/fs/nfsd/nfsfh.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfsfh.c:1.2
--- enf/src/linux/2.4.17/fs/nfsd/nfsfh.c:1.1.1.1	Tue Feb 19 06:20:19 2002
+++ enf/src/linux/2.4.17/fs/nfsd/nfsfh.c	Tue Feb 19 12:38:00 2002
@@ -28,6 +28,8 @@
 static int nfsd_nr_verified;
 static int nfsd_nr_put;
 
+extern void            nfsd_setuser(struct svc_rqst *, struct svc_export *);
+
 
 struct nfsd_getdents_callback {
 	char *name;		/* name that was found. It already points to a buffer NAME_MAX+1 is size */
@@ -533,7 +535,7 @@
 	u32		error = 0;
 
 	dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
-
+	
 	if (!fhp->fh_dentry) {
 		kdev_t xdev;
 		ino_t xino;
@@ -544,7 +546,6 @@
 		if (rqstp->rq_vers == 3)
 			error = nfserr_badhandle;
 		if (fh->fh_version == 1) {
-			
 			datap = fh->fh_auth;
 			if (--data_left<0) goto out;
 			switch (fh->fh_auth_type) {
@@ -599,8 +600,9 @@
 		 * Look up the dentry using the NFS file handle.
 		 */
 		error = nfserr_stale;
-		if (rqstp->rq_vers == 3)
+		if (rqstp->rq_vers == 3) {
 			error = nfserr_badhandle;
+		}
 
 		if (fh->fh_version == 1) {
 			/* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
@@ -675,7 +677,6 @@
 	if (!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)) {
 		if (exp->ex_dentry != dentry) {
 			struct dentry *tdentry = dentry;
-
 			do {
 				tdentry = tdentry->d_parent;
 				if (exp->ex_dentry == tdentry)
Index: enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c
diff -u enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c:1.3
--- enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c:1.1.1.1	Tue Feb 19 06:20:27 2002
+++ enf/src/linux/2.4.17/fs/nfsd/nfsxdr.c	Mon Mar 11 22:20:12 2002
@@ -14,6 +14,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr.h>
+#include <linux/nfsd/xdr3.h>
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
@@ -135,12 +136,14 @@
 encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
 {
 	int type = (inode->i_mode & S_IFMT);
+        static unsigned long	lasttime;
+        struct svc_export  	*expp;
 
 	*p++ = htonl(nfs_ftypes[type >> 12]);
 	*p++ = htonl((u32) inode->i_mode);
 	*p++ = htonl((u32) inode->i_nlink);
-	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
-	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
+	*p++ = htonl((u32) rmap_ruid(rqstp, inode->i_uid));
+	*p++ = htonl((u32) rmap_rgid(rqstp, inode->i_gid));
 
 	if (S_ISLNK(type) && inode->i_size > NFS_MAXPATHLEN) {
 		*p++ = htonl(NFS_MAXPATHLEN);
@@ -157,7 +160,25 @@
 	*p++ = htonl((u32) inode->i_ino);
 	*p++ = htonl((u32) inode->i_atime);
 	*p++ = 0;
-	*p++ = htonl((u32) lease_get_mtime(inode));
+
+        /* make readdir persist (force clients not to cache)
+	 * 
+         * THIS IS NECESSARY FOR FILE CLOAKING
+         * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+         */
+        expp = nfs3svc_rqst2exp(rqstp);
+        if(expp && (expp->ex_opaque[ENF_TCLIST][ENF_TUID] || expp->ex_opaque[ENF_TCLIST][ENF_TGID])
+		&& inode->i_mode & S_IFDIR && (expp->ex_flags & NFSEXP_NOCLIENTCACHE)) {
+                if(CURRENT_TIME <= lasttime) {
+                        lasttime++;
+                } else {
+                        lasttime = CURRENT_TIME;
+                }
+                *p++ = ((u32) lasttime);
+        } else {
+                *p++ = ((u32) lease_get_mtime(inode));
+        }
+
 	*p++ = 0;
 	*p++ = htonl((u32) inode->i_ctime);
 	*p++ = 0;
@@ -393,6 +414,35 @@
 {
 	u32	*p = cd->buffer;
 	int	buflen, slen;
+        struct dentry           *dentry;
+        struct svc_export       *exp = NULL;
+
+	/*
+	dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
+			namlen, name, offset, ino);
+	 */
+
+        /* file cloaking */
+        if(cd && cd->dirfh) {
+                exp = cd->dirfh->fh_export;
+
+                dentry = lookup_one_len(name, cd->dirfh->fh_dentry, namlen);
+                if(!IS_ERR(dentry) && dentry) {
+                        /* check for file cloaking */
+                        int iscl = 0;
+
+                        if (exp) {
+                        	iscl = clist_iscloaked(exp, dentry->d_inode);
+                        }
+
+                        dput(dentry);
+
+                        if (iscl) {
+                                /* perform file cloaking */
+                                return 0;
+                        }
+                }
+        }
 
 	/*
 	dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
Index: enf/src/linux/2.4.17/fs/nfsd/vfs.c
diff -u enf/src/linux/2.4.17/fs/nfsd/vfs.c:1.1.1.1 enf/src/linux/2.4.17/fs/nfsd/vfs.c:1.2
--- enf/src/linux/2.4.17/fs/nfsd/vfs.c:1.1.1.1	Tue Feb 19 06:20:12 2002
+++ enf/src/linux/2.4.17/fs/nfsd/vfs.c	Tue Feb 19 12:38:00 2002
@@ -41,8 +41,8 @@
 #include <linux/nfsd/xdr3.h>
 #endif /* CONFIG_NFSD_V3 */
 #include <linux/nfsd/nfsfh.h>
+#include <linux/nfsd/enf.h>
 #include <linux/quotaops.h>
-
 #include <asm/uaccess.h>
 
 #define NFSDDBG_FACILITY		NFSDDBG_FILEOP
@@ -179,7 +179,15 @@
 	err = fh_compose(resfh, exp, dentry, fhp);
 	if (!err && !dentry->d_inode)
 		err = nfserr_noent;
+
+	/* check for file cloaking */
+	if(exp && dentry && clist_iscloaked(exp, dentry->d_inode)) {
+                /* perform file cloaking */
+	        return nfserr_perm;
+	}
+
 out:
+
 	return err;
 
 out_nfserr:
@@ -822,7 +830,7 @@
 		goto out;
 
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
-	if (err)
+	if (err) 
 		goto out;
 
 	dentry = fhp->fh_dentry;
@@ -1483,7 +1491,7 @@
 
 	if (acc == MAY_NOP)
 		return 0;
-#if 0
+
 	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
 		acc,
 		(acc & MAY_READ)?	" read"  : "",
@@ -1499,7 +1507,16 @@
 		IS_RDONLY(inode)?	" ro" : "");
 	dprintk("      owner %d/%d user %d/%d\n",
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
-#endif
+
+	/* file cloaking effects permissions
+	 * IF inode is cloaked THEN there is no access to it
+	 * ELSE proceede with standard UNIX convention
+         */
+	if(clist_iscloaked(exp, dentry->d_inode))
+	{
+		/* perform cloaking */
+		return nfserr_perm;
+	}
 
 	/* only care about readonly exports for files and
 	 * directories. links don't have meaningful write access,
Index: enf/src/linux/2.4.17/include/linux/nfsd/auth.h
diff -u enf/src/linux/2.4.17/include/linux/nfsd/auth.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/auth.h:1.2
--- enf/src/linux/2.4.17/include/linux/nfsd/auth.h:1.1.1.1	Tue Feb 19 10:34:22 2002
+++ enf/src/linux/2.4.17/include/linux/nfsd/auth.h	Tue Feb 19 12:38:27 2002
@@ -12,34 +12,11 @@
 
 #ifdef __KERNEL__
 
-#define nfsd_luid(rq, uid)	((u32)(uid))
-#define nfsd_lgid(rq, gid)	((u32)(gid))
-#define nfsd_ruid(rq, uid)	((u32)(uid))
-#define nfsd_rgid(rq, gid)	((u32)(gid))
-
 /*
  * Set the current process's fsuid/fsgid etc to those of the NFS
  * client user
  */
 void		nfsd_setuser(struct svc_rqst *, struct svc_export *);
-
-#if 0
-/*
- * These must match the actual size of uid_t and gid_t
- */
-#define UGID_BITS		(8 * sizeof(uid_t))
-#define UGID_SHIFT		8
-#define UGID_MASK		((1 << UGID_SHIFT) - 1)
-#define UGID_NRENTRIES		((1 << (UGID_BITS - UGID_SHIFT)) + 1)
-#define UGID_NONE		((unsigned short)-1)
-
-typedef struct svc_uidmap {
-	uid_t *			um_ruid[UGID_NRENTRIES];
-	uid_t *			um_luid[UGID_NRENTRIES];
-	gid_t *			um_rgid[UGID_NRENTRIES];
-	gid_t *			um_lgid[UGID_NRENTRIES];
-} svc_uidmap;
-#endif
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_NFSD_AUTH_H */
Index: enf/src/linux/2.4.17/include/linux/nfsd/enf.h
diff -u /dev/null enf/src/linux/2.4.17/include/linux/nfsd/enf.h:1.2
--- /dev/null	Tue Mar 19 02:10:53 2002
+++ enf/src/linux/2.4.17/include/linux/nfsd/enf.h	Mon Mar 11 22:25:11 2002
@@ -0,0 +1,269 @@
+/*
+ * include/linux/nfsd/enf.h
+ *
+ * Enhanced NFS Features
+ *
+ * supported feature set:
+ *     uid/gid mapping
+ *     file cloaking
+ *
+ * Wed Sep 19 16:12:05 2001
+ * Joseph Spadavecchia [JES] <joseph@cs.sunysb.edu>
+ * Nenad Dedic <nenad@cs.bu.edu>
+ */
+
+#ifndef LINUX_NFSD_AUTH_H
+#define LINUX_NFSD_AUTH_H
+
+#ifdef __KERNEL__
+
+#include <asm/types.h>
+#include <linux/nfsd/const.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/export.h>
+#include <linux/string.h>
+
+#define ENF_TRMAP	0
+#define ENF_TCLIST	1
+#define ENF_MAXTYPE	2
+
+#define ENF_TUID	0
+#define ENF_TGID	1	
+
+#define ENF_HSRC	0
+#define ENF_HDST	1
+
+#define ENF_MAXIDLEN  NFSCLNT_IDMAX + NFS_MAXPATHLEN 
+
+#define ENF_HASH_FUNCTION(x) ((x) % ENF_HASH_LEN)
+#define ENF_HASH_INIT(x)	do { \
+					int i; \
+					for(i = 0; i < ENF_HASH_LEN; i++) \
+						x[i][ENF_HSRC] = i + 1; \
+				} while(0); \
+
+/* align mask bits with inode bits */				
+#define ENF_MASK2MODE(mask) mask = (mask & 0x0077) | \
+				((mask << 4) & 0x7000) | \
+				((mask & 0x1000) >> 4);
+
+uid_t rmap_ruid(struct svc_rqst *, uid_t);
+gid_t rmap_rgid(struct svc_rqst *, gid_t);
+uid_t rmap_luid(uid_t ruid, struct svc_export *);
+gid_t rmap_lgid(gid_t rgid, struct svc_export *);
+
+struct svc_export* enf_find_exp(char *, char *);
+
+/* struct for maintaining a global list
+ * of definition lists
+ * (can contain either rmaps or clists)
+ */
+struct enf_dl {
+	/* identifies a rmap definition entry */
+	char ed_id[ENF_MAXIDLEN]; 
+
+	/* rmap + cloaking uid and gid information */
+	struct list_head  ed_opaque[ENF_MAXTYPE][2]; 
+
+	int ed_refcnt[ENF_MAXTYPE]; /* number of references to this definition */
+
+	struct list_head ed_list;
+};
+
+/* range mapping list element */
+struct enf_rmap {
+	unsigned char er_map:1;      /* 1 for map, 0 for squash */
+
+	union {
+		uid_t uid; /* lower bound */
+		gid_t gid;
+	} u_lo;
+
+	union {
+		uid_t uid; /* lower bound */
+		gid_t gid;
+	} u_hi;
+
+	union {
+		uid_t uid; /* im_lo will be mapped to im_mapto */
+			   /* and im_lo + 1 to im_mapto + 1 */ 
+		gid_t gid;
+	} u_mapto;
+ 
+	struct list_head er_list;   
+};
+
+/* file cloaking list element */
+struct enf_clist {
+	umode_t ec_mask; /* 15 14 13 12 11 10 8    7 6  5  4  3  2  1  0  */
+			 /* u  g  t           show   gr gw gx    or ow ox */
+
+	union {
+		uid_t uid; /* lower bound */
+		gid_t gid;
+	} u_lo;
+
+	union {
+		uid_t uid; /* lower bound */
+		gid_t gid;
+	} u_hi;
+
+	union {
+		uid_t uid; /* im_lo will be mapped to im_mapto */
+			   /* and im_lo + 1 to im_mapto + 1 */ 
+		gid_t gid;
+	} u_mapto;
+ 
+	struct list_head ec_list;   
+};
+
+/**
+ * Determine if a inode should be cloaked for a 
+ * particular client and export.
+ * IN:
+ * 	@expp: pointer to the svc_export of the request
+ *	@inodep: pointer to inode  
+ * OUT:
+ * 	returns 1 IF cloaking is to be done 
+ * 	ELSE returns 0
+ *
+ * (This function assumes invocation under exp locked context.) 
+ */
+static inline int clist_iscloaked(struct svc_export *expp, struct inode *inodep)
+{
+	char b_and, b_show;
+	struct enf_clist *tmpp;
+	struct list_head *index;
+	uid_t	fuid;
+	gid_t	fgid;
+	umode_t mask;
+	umode_t mode;
+	int i_hv;
+	struct list_head * uidlist, * gidlist;
+
+	b_and = 0;
+	b_show = 0;
+
+	if(!inodep) {
+		goto out;
+	}
+
+	/* IF this current user owns the file 
+         * Then the file is VISIBLE
+         */
+	if(current->fsuid == inodep->i_uid) {
+		goto out;
+	}
+
+	uidlist = expp->ex_opaque[ENF_TCLIST][ENF_TUID];
+	gidlist = expp->ex_opaque[ENF_TCLIST][ENF_TGID];
+
+	if(!uidlist && !gidlist) {
+		goto out;
+	}
+
+	fuid = inodep->i_uid;
+	fgid = inodep->i_gid;
+	mode = inodep->i_mode; 
+
+	i_hv = ENF_HASH_FUNCTION(fuid);
+
+        /* IF the client/export has UID file
+         * cloaking information THEN check
+         * if this file should be cloaked
+         */
+	if(uidlist) {
+		/* check the cloaking hash */
+		if(expp->ex_cuid[i_hv][ENF_HSRC] != fuid) {
+			list_for_each(index, uidlist) {
+				tmpp = list_entry(index, struct enf_clist, ec_list);
+		
+				if(fuid >= tmpp->u_lo.uid && fuid <= tmpp->u_hi.uid) {
+						/* simple hash replacement */
+						mask = tmpp->ec_mask;
+						b_show = ((mask & 0x0100) != 0);
+						expp->ex_cuid[i_hv][ENF_HSRC] = fuid;
+						expp->ex_cuid[i_hv][ENF_HDST] = mask;
+						goto check_cloak;
+				}
+			}
+		} else {
+			mask = expp->ex_cuid[i_hv][ENF_HDST];
+			b_show = ((mask & 0x0100) != 0);
+			goto check_cloak;
+		}
+	
+	}
+
+	i_hv = ENF_HASH_FUNCTION(fgid);
+
+	/* IF the client/export has GID file
+	 * cloaking information THEN check
+	 * if this file should be CLOAKED 
+	 */
+	if(gidlist) {
+		if(expp->ex_cgid[i_hv][ENF_HSRC] != fgid) {
+			list_for_each(index, gidlist) {
+				tmpp = list_entry(index, struct enf_clist, ec_list);
+		
+				if(fgid >= tmpp->u_lo.gid && fgid <= tmpp->u_hi.gid) {
+                                                /* simple hash replacement */
+                                                mask = tmpp->ec_mask;
+						b_show = ((mask & 0x0100) != 0);
+                                                expp->ex_cgid[i_hv][ENF_HSRC] = fgid;
+                                                expp->ex_cgid[i_hv][ENF_HDST] = mask;
+						goto check_cloak;
+				}
+			}
+		} else {
+                        mask = expp->ex_cgid[i_hv][ENF_HDST];
+			b_show = ((mask & 0x0100) != 0);
+			goto check_cloak;
+		}
+	}
+
+	/* IF the file is owned by a uid and gid that are 
+	 * not cloaked THEN visible 
+ 	 */
+	goto out;
+
+check_cloak:
+
+	/* IF the file is world rwx or ugt
+         * AND the admin mask allows other or ugt
+	 * THEN the file is visible IF b_show = 1
+	 * ELSE IF b_show = 0 the file is
+	 * hidden
+	 */
+	if(mode & (mask & 0x7007)) {
+		b_and = 1;
+		goto out;
+	}
+
+	/* IF the file has any group bits on
+	 * AND the fcloak mask allows group
+	 * AND the current user is a member of
+	 * the files's group then THEN file 
+	 * is visible IF b_show = 1
+	 * ELSE IF b_show = 0 the file
+	 * is hidden
+	 */
+	if((mode & (0x0070 & mask)) && 
+	   in_group_p(fgid)) {
+		b_and = 1;
+		goto out;
+	}
+
+	/* IF we arrive here THEN 
+	 * IF b_show = 1
+	 * the file is hidden
+	 * ELSE IF b_show = 0 the 
+	 * file is visible
+	 */
+	b_and = 0;
+out:
+	return b_and ^ b_show;
+}
+
+#endif /* __KERNEL__ */
+#endif /* LINUX_NFSD_ENF_H */
Index: enf/src/linux/2.4.17/include/linux/nfsd/export.h
diff -u enf/src/linux/2.4.17/include/linux/nfsd/export.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/export.h:1.4
--- enf/src/linux/2.4.17/include/linux/nfsd/export.h:1.1.1.1	Tue Feb 19 10:34:20 2002
+++ enf/src/linux/2.4.17/include/linux/nfsd/export.h	Mon Mar 11 22:25:11 2002
@@ -32,28 +32,29 @@
 #define NFSEXP_ALLSQUASH	0x0008
 #define NFSEXP_ASYNC		0x0010
 #define NFSEXP_GATHERED_WRITES	0x0020
-#define NFSEXP_UIDMAP		0x0040
+#define NFSEXP_RMAP		0x0040		/* range mapping */
 #define NFSEXP_KERBEROS		0x0080		/* not available */
 #define NFSEXP_SUNSECURE	0x0100
 #define NFSEXP_CROSSMNT		0x0200
 #define NFSEXP_NOSUBTREECHECK	0x0400
 #define	NFSEXP_NOAUTHNLM	0x0800		/* Don't authenticate NLM requests - just trust */
 #define NFSEXP_MSNFS		0x1000	/* do silly things that MS clients expect */
-#define NFSEXP_ALLFLAGS		0x1FFF
-
+#define NFSEXP_NOCLIENTCACHE	0x2000  /* cause NFS server to turn off _client_ caching to assist file cloaking */
+#define NFSEXP_ALLFLAGS		0x2FFF
 
 #ifdef __KERNEL__
 
 /* The following are hashtable sizes and must be powers of 2 */
 #define NFSCLNT_EXPMAX		16
 
+#define ENF_HASH_LEN 32 
+
 struct svc_client {
 	struct svc_client *	cl_next;
 	char			cl_ident[NFSCLNT_IDMAX];
 	int			cl_idlen;
 	int			cl_naddr;
 	struct in_addr		cl_addr[NFSCLNT_ADDRMAX];
-	struct svc_uidmap *	cl_umap;
 	struct svc_export *	cl_export[NFSCLNT_EXPMAX];
 };
 
@@ -69,6 +70,25 @@
 	ino_t			ex_ino;
 	uid_t			ex_anon_uid;
 	gid_t			ex_anon_gid;
+
+	/* range mapping hash tables */
+	uid_t			ex_ruid[ENF_HASH_LEN][2];
+	uid_t			ex_luid[ENF_HASH_LEN][2];
+	gid_t			ex_rgid[ENF_HASH_LEN][2];
+	gid_t			ex_lgid[ENF_HASH_LEN][2];
+
+	/* file cloaking hash tables */
+	uid_t			ex_cuid[ENF_HASH_LEN][2];
+	gid_t			ex_cgid[ENF_HASH_LEN][2];
+
+	/* ex_opaque:
+	 *   ________0________________1________
+	 * 0| uid rmap list  |  gid rmap list  |	
+	 *  |----------------|-----------------|
+	 * 1| uid clist list |  gid clist list |
+	 *   ----------------------------------
+	 */
+	struct list_head	*ex_opaque[2][2]; 
 };
 
 #define EX_SECURE(exp)		(!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
@@ -94,7 +114,7 @@
 					char *path, struct knfsd_fh *, int maxsize);
 int			nfserrno(int errno);
 void			exp_nlmdetach(void);
-
+struct svc_client *     get_clients(void);
 
 #endif /* __KERNEL__ */
 
Index: enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h
diff -u enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h:1.2
--- enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h:1.1.1.1	Tue Feb 19 10:34:24 2002
+++ enf/src/linux/2.4.17/include/linux/nfsd/nfsd.h	Tue Feb 19 12:38:27 2002
@@ -19,13 +19,36 @@
 #include <linux/nfsd/debug.h>
 #include <linux/nfsd/nfsfh.h>
 #include <linux/nfsd/export.h>
+#include <linux/nfsd/enf.h>
 #include <linux/nfsd/auth.h>
 #include <linux/nfsd/stats.h>
 #include <linux/nfsd/interface.h>
+
 /*
  * nfsd version
  */
 #define NFSD_VERSION		"0.5"
+
+
+#if 1
+# define ASSERT(EX)      \
+do {    \
+    if (!(EX)) {        \
+        printk(KERN_CRIT "ASSERTION FAILED: %s at %s:%d (%s)\n", #EX,   \
+               __FILE__, __LINE__, __FUNCTION__);       \
+        (*((char *)0))=0;       \
+    }   \
+} while (0)
+#else
+# define ASSERT(EX)
+#endif
+
+
+#if 1 
+# define DBG printk("<1> %s:%d:%s\n",__FILE__,__LINE__,__FUNCTION__)
+#else
+# define DBG
+#endif
 
 #ifdef __KERNEL__
 /*
Index: enf/src/linux/2.4.17/include/linux/nfsd/syscall.h
diff -u enf/src/linux/2.4.17/include/linux/nfsd/syscall.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/syscall.h:1.3
--- enf/src/linux/2.4.17/include/linux/nfsd/syscall.h:1.1.1.1	Tue Feb 19 10:34:21 2002
+++ enf/src/linux/2.4.17/include/linux/nfsd/syscall.h	Mon Mar 11 22:25:11 2002
@@ -15,6 +15,7 @@
 # include <linux/types.h>
 # include <linux/in.h>
 #endif 
+
 #include <linux/posix_types.h>
 #include <linux/nfsd/const.h>
 #include <linux/nfsd/export.h>
@@ -34,7 +35,7 @@
 #define NFSCTL_DELCLIENT	2	/* Remove an NFS client. */
 #define NFSCTL_EXPORT		3	/* export a file system. */
 #define NFSCTL_UNEXPORT		4	/* unexport a file system. */
-#define NFSCTL_UGIDUPDATE	5	/* update a client's uid/gid map. */
+#define NFSCTL_ENF   		5	/* update uid/gid range mapping or cloaking info. */
 #define NFSCTL_GETFH		6	/* get an fh by ino (used by mountd) */
 #define NFSCTL_GETFD		7	/* get an fh by path (used by mountd) */
 #define	NFSCTL_GETFS		8	/* get an fh by path with max FH len */
@@ -66,15 +67,56 @@
 	__kernel_gid_t		ex_anon_gid;
 };
 
-/* UGIDUPDATE */
-struct nfsctl_uidmap {
-	char *			ug_ident;
-	__kernel_uid_t		ug_uidbase;
-	int			ug_uidlen;
-	__kernel_uid_t *	ug_udimap;
-	__kernel_gid_t		ug_gidbase;
-	int			ug_gidlen;
-	__kernel_gid_t *	ug_gdimap;
+/* ENF arguments */
+struct nfsctl_enf {
+/* functions (ne_func) */ 
+#define	ENF_ADD		1 
+#define ENF_DELETE	2
+#define ENF_FLUSH	3
+
+	/* The type of information we are adding 
+	 */
+	unsigned char	ne_type; /* range map (ENF_TRMAP) */
+				 /* file cloak (ENF_TCLIST) */
+
+	/* This is only set for enf_add().  It the the key in the global
+	 * def. list that uniquely identifies the /etc/exports entry 
+	 * this belongs to.  It alows us to save memory by storing
+	 * one copy of a range mapping or cloaking definition for all
+	 * clients connected an export
+	 */
+	char	ne_id[ENF_MAXIDLEN];
+
+	/* Used to identify an actual client and export.
+	 * nr_client is always a FQDN, where nr_id may
+	 * have non FQDN client portion
+	 */
+	char	ne_client[NFSCLNT_IDMAX];
+	char	ne_path[NFS_MAXPATHLEN];
+	   
+	unsigned short  ne_func:8,    /* function to perform (e.g. ENF_ADD) */
+		        ne_uid:1,     /* 1 for uidmap, 0 for gidmap */
+	  	        ne_generic:6; /* 6 bits future features */ 
+	    
+	umode_t ne_mask; /*file-cloaking mask */
+			 /* 13   12 11 10 8  7 6  5  4  3  2  1  0  */
+			 /* show    u  g  t    gr gw gx    or ow ox */
+	union {
+		uid_t	uid;
+		gid_t	gid;
+	} u_lo;
+
+	union {
+		uid_t	uid;
+		gid_t	gid;
+	} u_hi;
+
+	/* Below only used to add range-mapping information */
+	unsigned char	ne_map:1; /* 1 for mapping 0 for squashing */
+	union {
+		uid_t	uid;
+		gid_t	gid;
+	} u_mapto;
 };
 
 /* GETFH */
@@ -108,7 +150,7 @@
 		struct nfsctl_svc	u_svc;
 		struct nfsctl_client	u_client;
 		struct nfsctl_export	u_export;
-		struct nfsctl_uidmap	u_umap;
+	        struct nfsctl_enf	u_enf;
 		struct nfsctl_fhparm	u_getfh;
 		struct nfsctl_fdparm	u_getfd;
 		struct nfsctl_fsparm	u_getfs;
@@ -116,7 +158,7 @@
 #define ca_svc		u.u_svc
 #define ca_client	u.u_client
 #define ca_export	u.u_export
-#define ca_umap		u.u_umap
+#define ca_enf		u.u_enf
 #define ca_getfh	u.u_getfh
 #define ca_getfd	u.u_getfd
 #define	ca_getfs	u.u_getfs
@@ -141,6 +183,9 @@
 extern int		exp_delclient(struct nfsctl_client *ncp);
 extern int		exp_export(struct nfsctl_export *nxp);
 extern int		exp_unexport(struct nfsctl_export *nxp);
+extern int		enf_add(struct nfsctl_enf *data);
+extern int		enf_delete(struct nfsctl_enf *data);
+extern int		enf_flush(struct nfsctl_enf *data);
 
 #endif /* __KERNEL__ */
 
Index: enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h
diff -u enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h:1.1.1.1 enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h:1.2
--- enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h:1.1.1.1	Tue Feb 19 10:34:25 2002
+++ enf/src/linux/2.4.17/include/linux/nfsd/xdr3.h	Tue Feb 19 12:38:27 2002
@@ -298,5 +298,45 @@
 				int namlen, loff_t offset, ino_t ino,
 				unsigned int);
 
+/* [JES]
+ * Return the svc_export from the @rqstp svc_request struct.
+ */
+static __inline__ struct svc_export *nfs3svc_rqst2exp(struct svc_rqst *rqstp)
+{
+        struct svc_export       *retp = NULL;
+        struct svc_fh           fh;
+        struct nfsd3_attrstat   response; /* for nfs3 */
+
+        if(!rqstp) {
+                goto out;
+        }
+
+        /* get the export this request is referring to */
+        if (rqstp->rq_vers == 2)
+        {
+                /* HACK v2! */
+                memcpy((void *)(&fh), (void *)(rqstp->rq_resp), sizeof(fh));
+        }
+        else if (rqstp->rq_vers == 3)
+        {
+                /* HACK v3! */
+                memcpy((void *)(&response), (void *)(rqstp->rq_resp),
+                        sizeof(struct nfsd3_attrstat));
+
+                memcpy((void *)(&fh), (void*)(&(response.fh)), sizeof(fh));
+        }
+        else
+        {
+                printk(KERN_DEBUG "EXP: exp_rqst2exp() -- unsuported NFS version %d\n",
+                        rqstp->rq_vers);
+
+                goto out_unlock;
+        }
+out_unlock:
+        retp = (fh.fh_export);
+out:
+        return retp;
+}
+
 
 #endif /* _LINUX_NFSD_XDR3_H */
