
nfsd_cross_mnt() is called by OP_LOOKUP and OP_READDIR processing to determine
if a mount point is to be crossed, and to set the correct export.
If a mount point is to be crossed, the request pseudoflavor is checked against
the to-be-crossed export's supported psuedoflavors.

For NFSv4, for both OP_LOOKUP and OP_READDIR processing, NFS4ERR_WRONG_SEC
is returned if the request pseudoflavor is not
supported by the to-be-crossed mountpoint. For NFSv2/3 -EPERM is returned.

OP_SECINFO is given a directory file handle and a name, and therefore
needs to call nfsd_lookup() to resolve the name's export struct to query for
the list of supported pseudoflavors associated with the name.
If the lookup called by OP_SECINFO processing crosses a mount point,
the export of the mountpoint needs to be queried for supported pseudoflavors.

For NFSv4, nfsd_cross_mnt() needs to perform the task of returning the
supported pseudoflavors for the mount point, and so needs the xdr struct
nfsd4_secinfo parameter added.

In preparation for OP_SECINFO processing:
Add a void *secinfo parameter to nfsd_cross_mnt() to enable NFSv4 OP_SECINFO
to return a mountpoints supported pseudoflavors.
Add a NULL pointer for this new void *secinfo to readdir's nfsd_cross_mnt()
Rename nfsd_lookup to __nfsd_lookup and add a void *secinfo parameter.
Declare nfsd_lookup as a wrapper to __nfsd_lookup which is called with a NULL
for the new void *secinfo parameter.
Declare a new function nfs4_set_secinfo_xmnt() which will return
nfserr_wrongsec for NFSv4 and nfserr_perm for NFSv2/3.

Signed-off-by: Andy Adamson <andros@citi.umich.edu>
---

---

 linux-2.6.18-rc5-andros/fs/nfsd/nfs4proc.c        |    6 ++++++
 linux-2.6.18-rc5-andros/fs/nfsd/nfs4xdr.c         |    2 +-
 linux-2.6.18-rc5-andros/fs/nfsd/vfs.c             |   20 +++++++++++++++-----
 linux-2.6.18-rc5-andros/include/linux/nfsd/nfsd.h |   12 ++++++++++--
 4 files changed, 32 insertions(+), 8 deletions(-)

diff -puN fs/nfsd/nfs4proc.c~nfsd-secinfo-vfs-changes fs/nfsd/nfs4proc.c
--- linux-2.6.18-rc5/fs/nfsd/nfs4proc.c~nfsd-secinfo-vfs-changes	2006-10-11 17:36:46.000000000 -0400
+++ linux-2.6.18-rc5-andros/fs/nfsd/nfs4proc.c	2006-10-11 17:36:46.000000000 -0400
@@ -67,6 +67,12 @@ fh_dup2(struct svc_fh *dst, struct svc_f
 	*dst = *src;
 }
 
+int
+nfs4_set_secinfo_xmnt(struct svc_export *exp, void *secinfo)
+{
+	return nfserr_wrongsec;
+}
+
 static int
 do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
diff -puN fs/nfsd/nfs4xdr.c~nfsd-secinfo-vfs-changes fs/nfsd/nfs4xdr.c
--- linux-2.6.18-rc5/fs/nfsd/nfs4xdr.c~nfsd-secinfo-vfs-changes	2006-10-11 17:36:46.000000000 -0400
+++ linux-2.6.18-rc5-andros/fs/nfsd/nfs4xdr.c	2006-10-11 17:36:46.000000000 -0400
@@ -1861,7 +1861,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
 
 	exp_get(exp);
 	if (d_mountpoint(dentry)) {
-		nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
+		nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp, NULL);
 		if (nfserr) {
 			goto out_put;
 		}
diff -puN fs/nfsd/vfs.c~nfsd-secinfo-vfs-changes fs/nfsd/vfs.c
--- linux-2.6.18-rc5/fs/nfsd/vfs.c~nfsd-secinfo-vfs-changes	2006-10-11 17:36:46.000000000 -0400
+++ linux-2.6.18-rc5-andros/fs/nfsd/vfs.c	2006-10-11 17:36:46.000000000 -0400
@@ -91,10 +91,13 @@ static struct raparms *		raparm_cache;
  * a mount point.
  * Returns -EAGAIN leaving *dpp and *expp unchanged, 
  *  or nfs_ok having possibly changed *dpp and *expp
+ *  or nfserr_perm for v2/3; nfserr_wrongsec for v4 leaving
+ *  *dpp and *expp unchanged.
+ *
  */
 int
 nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, 
-		        struct svc_export **expp)
+		        struct svc_export **expp, void *secinfo)
 {
 	struct svc_export *exp = *expp, *exp2 = NULL;
 	struct dentry *dentry = *dpp;
@@ -115,7 +118,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, s
 		/* successfully crossed mount point.
 		 * check security flavor access to new export */
 		if (!EX_ACCESS(exp2, rqstp->rq_pflavindex)) {
-			err = nfserr_perm;
+			err = nfs4_set_secinfo_xmnt(exp2, secinfo);
 			exp_put(exp2);
 			dput(mounts);
 			mntput(mnt);
@@ -147,8 +150,8 @@ out:
  *      NeilBrown <neilb@cse.unsw.edu.au>
  */
 int
-nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
-					int len, struct svc_fh *resfh)
+__nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
+			int len, struct svc_fh *resfh, void *si)
 {
 	struct svc_export	*exp;
 	struct dentry		*dparent;
@@ -215,7 +218,7 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
 		 * check if we have crossed a mount point ...
 		 */
 		if (d_mountpoint(dentry)) {
-			if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
+			if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp, si))) {
 				dput(dentry);
 				goto out;
 			}
@@ -238,6 +241,13 @@ out_nfserr:
 	goto out;
 }
 
+int
+nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
+				int len, struct svc_fh *resfh)
+{
+	return __nfsd_lookup(rqstp, fhp, name, len, resfh, NULL);
+}
+
 /*
  * Set various file attributes.
  * N.B. After this call fhp needs an fh_put
diff -puN include/linux/nfsd/nfsd.h~nfsd-secinfo-vfs-changes include/linux/nfsd/nfsd.h
--- linux-2.6.18-rc5/include/linux/nfsd/nfsd.h~nfsd-secinfo-vfs-changes	2006-10-11 17:36:46.000000000 -0400
+++ linux-2.6.18-rc5-andros/include/linux/nfsd/nfsd.h	2006-10-11 17:36:46.000000000 -0400
@@ -70,10 +70,12 @@ int		nfsd_dispatch(struct svc_rqst *rqst
 int		fh_lock_parent(struct svc_fh *, struct dentry *);
 int		nfsd_racache_init(int);
 void		nfsd_racache_shutdown(void);
-int		nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
-		                struct svc_export **expp);
+int		nfsd_cross_mnt(struct svc_rqst *, struct dentry **,
+		                struct svc_export **, void *);
 int		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
 				const char *, int, struct svc_fh *);
+int		__nfsd_lookup(struct svc_rqst *, struct svc_fh *,
+				const char *, int, struct svc_fh *, void *);
 int		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
 				struct iattr *, int, time_t);
 #ifdef CONFIG_NFSD_V4
@@ -326,8 +328,14 @@ static inline int is_fsid(struct svc_fh 
 (FATTR4_WORD1_MODE              | FATTR4_WORD1_OWNER         | FATTR4_WORD1_OWNER_GROUP     \
  | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
 
+/* On crossing a mount point, NFSv4 needs to return nfserr_wrongsec and
+ * potentially stuff a secinfo struct NFSv2/3 needs to return nfserr_perm. */
+int nfs4_set_secinfo_xmnt(struct svc_export *exp, void *v_secinfo);
+#else /* CONFIG_NFSD_V4 */
+static inline int nfs4_set_secinfo_xmnt(struct svc_export *exp, void *v_secinfo) {return nfserr_perm;}
 #endif /* CONFIG_NFSD_V4 */
 
+
 #endif /* __KERNEL__ */
 
 #endif /* LINUX_NFSD_NFSD_H */
_
