vserver 1.9.5.x5
[linux-2.6.git] / fs / nfsd / nfsfh.c
index 369ccea..0cf1061 100644 (file)
@@ -56,7 +56,7 @@ int nfsd_acceptable(void *expv, struct dentry *dentry)
                /* make sure parents give x permission to user */
                int err;
                parent = dget_parent(tdentry);
-               err = permission(parent->d_inode, S_IXOTH, NULL);
+               err = permission(parent->d_inode, MAY_EXEC, NULL);
                if (err < 0) {
                        dput(parent);
                        break;
@@ -71,6 +71,35 @@ int nfsd_acceptable(void *expv, struct dentry *dentry)
        return rv;
 }
 
+/* Type check. The correct error return for type mismatches does not seem to be
+ * generally agreed upon. SunOS seems to use EISDIR if file isn't S_IFREG; a
+ * comment in the NFSv3 spec says this is incorrect (implementation notes for
+ * the write call).
+ */
+static inline int
+nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
+{
+       /* Type can be negative when creating hardlinks - not to a dir */
+       if (type > 0 && (mode & S_IFMT) != type) {
+               if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK)
+                       return nfserr_symlink;
+               else if (type == S_IFDIR)
+                       return nfserr_notdir;
+               else if ((mode & S_IFMT) == S_IFDIR)
+                       return nfserr_isdir;
+               else
+                       return nfserr_inval;
+       }
+       if (type < 0 && (mode & S_IFMT) == -type) {
+               if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK)
+                       return nfserr_symlink;
+               else if (type == -S_IFDIR)
+                       return nfserr_isdir;
+               else
+                       return nfserr_notdir;
+       }
+       return 0;
+}
 
 /*
  * Perform sanity checks on the dentry in a client's file handle.
@@ -87,7 +116,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
        struct knfsd_fh *fh = &fhp->fh_handle;
        struct svc_export *exp = NULL;
        struct dentry   *dentry;
-       struct inode    *inode;
        u32             error = 0;
 
        dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
@@ -153,8 +181,8 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                error = nfserr_perm;
                if (!rqstp->rq_secure && EX_SECURE(exp)) {
                        printk(KERN_WARNING
-                              "nfsd: request from insecure port (%08x:%d)!\n",
-                              ntohl(rqstp->rq_addr.sin_addr.s_addr),
+                              "nfsd: request from insecure port (%u.%u.%u.%u:%d)!\n",
+                              NIPQUAD(rqstp->rq_addr.sin_addr.s_addr),
                               ntohs(rqstp->rq_addr.sin_port));
                        goto out;
                }
@@ -190,10 +218,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
                        dentry = dget(exp->ex_dentry);
                else {
                        struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
-                               dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb,
-                                                            datap, data_left,
-                                                            fileid_type,
-                                                            nfsd_acceptable, exp);
+                       dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb,
+                                                    datap, data_left,
+                                                    fileid_type,
+                                                    nfsd_acceptable, exp);
                }
                if (dentry == NULL)
                        goto out;
@@ -223,37 +251,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
        }
        cache_get(&exp->h);
 
-       inode = dentry->d_inode;
-
-
-       /* Type check. The correct error return for type mismatches
-        * does not seem to be generally agreed upon. SunOS seems to
-        * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
-        * spec says this is incorrect (implementation notes for the
-        * write call).
-        */
-
-       /* Type can be negative when creating hardlinks - not to a dir */
-       if (type > 0 && (inode->i_mode & S_IFMT) != type) {
-               if (rqstp->rq_vers == 4 && (inode->i_mode & S_IFMT) == S_IFLNK)
-                       error = nfserr_symlink;
-               else if (type == S_IFDIR)
-                       error = nfserr_notdir;
-               else if ((inode->i_mode & S_IFMT) == S_IFDIR)
-                       error = nfserr_isdir;
-               else
-                       error = nfserr_inval;
-               goto out;
-       }
-       if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
-               if (rqstp->rq_vers == 4 && (inode->i_mode & S_IFMT) == S_IFLNK)
-                       error = nfserr_symlink;
-               else if (type == -S_IFDIR)
-                       error = nfserr_isdir;
-               else
-                       error = nfserr_notdir;
+       error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
+       if (error)
                goto out;
-       }
 
        /* Finally, check access permissions. */
        error = nfsd_permission(exp, dentry, access);
@@ -339,13 +339,16 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
                        ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type;
                if (ref_fh_fsid_type > 3)
                        ref_fh_fsid_type = 0;
-       }
-       /* make sure ref_fh type works for given export */
-       if (ref_fh_fsid_type == 1 &&
-           !(exp->ex_flags & NFSEXP_FSID)) {
-               /* if we don't have an fsid, we cannot provide one... */
-               ref_fh_fsid_type = 0;
-       }
+
+               /* make sure ref_fh type works for given export */
+               if (ref_fh_fsid_type == 1 &&
+                   !(exp->ex_flags & NFSEXP_FSID)) {
+                       /* if we don't have an fsid, we cannot provide one... */
+                       ref_fh_fsid_type = 0;
+               }
+       } else if (exp->ex_flags & NFSEXP_FSID)
+               ref_fh_fsid_type = 1;
+
        if (!old_valid_dev(ex_dev) && ref_fh_fsid_type == 0) {
                /* for newer device numbers, we must use a newer fsid format */
                ref_fh_version = 1;
@@ -367,7 +370,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
                printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
                       fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
 
-       fhp->fh_dentry = dentry; /* our internal copy */
+       fhp->fh_dentry = dget(dentry); /* our internal copy */
        fhp->fh_export = exp;
        cache_get(&exp->h);