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 --- --- 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 */ 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 */ _