nfsd4: recheck for secure ports in fh_verify
[sfrench/cifs-2.6.git] / fs / nfsd / nfsfh.c
index 7011d62acfc8dd3516b52961ad598a8371fcc08d..468f17a784416e96e11081d90230a8e6df4eec90 100644 (file)
@@ -95,6 +95,22 @@ nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
        return 0;
 }
 
+static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
+                                         struct svc_export *exp)
+{
+       /* Check if the request originated from a secure port. */
+       if (!rqstp->rq_secure && EX_SECURE(exp)) {
+               char buf[RPC_MAX_ADDRBUFLEN];
+               dprintk(KERN_WARNING
+                      "nfsd: request from insecure port %s!\n",
+                      svc_print_addr(rqstp, buf, sizeof(buf)));
+               return nfserr_perm;
+       }
+
+       /* Set user creds for this exportpoint */
+       return nfserrno(nfsd_setuser(rqstp, exp));
+}
+
 /*
  * Perform sanity checks on the dentry in a client's file handle.
  *
@@ -115,8 +131,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
        dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
 
        if (!fhp->fh_dentry) {
-               __u32 *datap=NULL;
-               __u32 tfh[3];           /* filehandle fragment for oldstyle filehandles */
+               struct fid *fid = NULL, sfid;
                int fileid_type;
                int data_left = fh->fh_size/4;
 
@@ -128,7 +143,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
 
                if (fh->fh_version == 1) {
                        int len;
-                       datap = fh->fh_auth;
                        if (--data_left<0) goto out;
                        switch (fh->fh_auth_type) {
                        case 0: break;
@@ -144,9 +158,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                                fh->fh_fsid[1] = fh->fh_fsid[2];
                        }
                        if ((data_left -= len)<0) goto out;
-                       exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap);
-                       datap += len;
+                       exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
+                                           fh->fh_auth);
+                       fid = (struct fid *)(fh->fh_auth + len);
                } else {
+                       __u32 tfh[2];
                        dev_t xdev;
                        ino_t xino;
                        if (fh->fh_size != NFS_FHSIZE)
@@ -167,18 +183,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        goto out;
                }
 
-               /* Check if the request originated from a secure port. */
-               error = nfserr_perm;
-               if (!rqstp->rq_secure && EX_SECURE(exp)) {
-                       char buf[RPC_MAX_ADDRBUFLEN];
-                       printk(KERN_WARNING
-                              "nfsd: request from insecure port %s!\n",
-                              svc_print_addr(rqstp, buf, sizeof(buf)));
-                       goto out;
-               }
-
-               /* Set user creds for this exportpoint */
-               error = nfserrno(nfsd_setuser(rqstp, exp));
+               error = nfsd_setuser_and_check_port(rqstp, exp);
                if (error)
                        goto out;
 
@@ -190,22 +195,22 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        error = nfserr_badhandle;
 
                if (fh->fh_version != 1) {
-                       tfh[0] = fh->ofh_ino;
-                       tfh[1] = fh->ofh_generation;
-                       tfh[2] = fh->ofh_dirino;
-                       datap = tfh;
+                       sfid.i32.ino = fh->ofh_ino;
+                       sfid.i32.gen = fh->ofh_generation;
+                       sfid.i32.parent_ino = fh->ofh_dirino;
+                       fid = &sfid;
                        data_left = 3;
                        if (fh->ofh_dirino == 0)
-                               fileid_type = 1;
+                               fileid_type = FILEID_INO32_GEN;
                        else
-                               fileid_type = 2;
+                               fileid_type = FILEID_INO32_GEN_PARENT;
                } else
                        fileid_type = fh->fh_fileid_type;
 
-               if (fileid_type == 0)
+               if (fileid_type == FILEID_ROOT)
                        dentry = dget(exp->ex_dentry);
                else {
-                       dentry = exportfs_decode_fh(exp->ex_mnt, datap,
+                       dentry = exportfs_decode_fh(exp->ex_mnt, fid,
                                        data_left, fileid_type,
                                        nfsd_acceptable, exp);
                }
@@ -227,18 +232,22 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                fhp->fh_export = exp;
                nfsd_nr_verified++;
        } else {
-               /* just rechecking permissions
-                * (e.g. nfsproc_create calls fh_verify, then nfsd_create does as well)
+               /*
+                * just rechecking permissions
+                * (e.g. nfsproc_create calls fh_verify, then nfsd_create
+                * does as well)
                 */
                dprintk("nfsd: fh_verify - just checking\n");
                dentry = fhp->fh_dentry;
                exp = fhp->fh_export;
-               /* Set user creds for this exportpoint; necessary even
+               /*
+                * Set user creds for this exportpoint; necessary even
                 * in the "just checking" case because this may be a
                 * filehandle that was created by fh_compose, and that
                 * is about to be used in another nfsv4 compound
-                * operation */
-               error = nfserrno(nfsd_setuser(rqstp, exp));
+                * operation.
+                */
+               error = nfsd_setuser_and_check_port(rqstp, exp);
                if (error)
                        goto out;
        }
@@ -286,16 +295,21 @@ out:
  * an inode.  In this case a call to fh_update should be made
  * before the fh goes out on the wire ...
  */
-static inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
-                            __u32 *datap, int *maxsize)
+static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
+               struct dentry *dentry)
 {
-       if (dentry == exp->ex_dentry) {
-               *maxsize = 0;
-               return 0;
-       }
+       if (dentry != exp->ex_dentry) {
+               struct fid *fid = (struct fid *)
+                       (fhp->fh_handle.fh_auth + fhp->fh_handle.fh_size/4 - 1);
+               int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
+               int subtreecheck = !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
 
-       return exportfs_encode_fh(dentry, datap, maxsize,
-                         !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+               fhp->fh_handle.fh_fileid_type =
+                       exportfs_encode_fh(dentry, fid, &maxsize, subtreecheck);
+               fhp->fh_handle.fh_size += maxsize * 4;
+       } else {
+               fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
+       }
 }
 
 /*
@@ -457,12 +471,8 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
                datap += len/4;
                fhp->fh_handle.fh_size = 4 + len;
 
-               if (inode) {
-                       int size = (fhp->fh_maxsize-len-4)/4;
-                       fhp->fh_handle.fh_fileid_type =
-                               _fh_update(dentry, exp, datap, &size);
-                       fhp->fh_handle.fh_size += size*4;
-               }
+               if (inode)
+                       _fh_update(fhp, exp, dentry);
                if (fhp->fh_handle.fh_fileid_type == 255)
                        return nfserr_opnotsupp;
        }
@@ -479,7 +489,6 @@ __be32
 fh_update(struct svc_fh *fhp)
 {
        struct dentry *dentry;
-       __u32 *datap;
 
        if (!fhp->fh_dentry)
                goto out_bad;
@@ -490,15 +499,10 @@ fh_update(struct svc_fh *fhp)
        if (fhp->fh_handle.fh_version != 1) {
                _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
        } else {
-               int size;
-               if (fhp->fh_handle.fh_fileid_type != 0)
+               if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
                        goto out;
-               datap = fhp->fh_handle.fh_auth+
-                       fhp->fh_handle.fh_size/4 -1;
-               size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
-               fhp->fh_handle.fh_fileid_type =
-                       _fh_update(dentry, fhp->fh_export, datap, &size);
-               fhp->fh_handle.fh_size += size*4;
+
+               _fh_update(fhp, fhp->fh_export, dentry);
                if (fhp->fh_handle.fh_fileid_type == 255)
                        return nfserr_opnotsupp;
        }