Data reads and writes should not need credentials, and most filesystems
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 10 Oct 2003 22:01:13 +0000 (22:01 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 10 Oct 2003 22:01:13 +0000 (22:01 +0000)
ignore the ucred argument.  NFS does, though, and FreeBSD-4.x had some
terrible hacks to associate credentials with data that only 'mostly' worked.
There were VM paging and buffer reconstitution cases which broke the
credentials even in 4.x.  The hacks were removed from DragonFly during
the VFS messaging reorganization.

In DragonFly credentials are checked on open() but no credentials are
required for read and write ops.  I had NFS just use the 'root' credential
for the RPC.  However, this breaks NFS mounts which do not use the -maproot
(server side) directive.  Really the bug is on the server side, but to
maintain general compatibility with NFS servers we have to provide a
non-root credential if root did not issue the I/O.  This commit hacks up
the NFS code (rather then hacking up the rest of the kernel) to restore
the hacks that were previously removed from the kernel.  Unfortunately it
can lead to a proliferation of ucred structures (FreeBSD-4.x did as well),
but that's the price we have to pay for now.

Report-by: Galen Sampson <galen_sampson@yahoo.com>
sys/vfs/nfs/nfs_node.c
sys/vfs/nfs/nfs_nqlease.c
sys/vfs/nfs/nfs_subs.c
sys/vfs/nfs/nfs_vfsops.c
sys/vfs/nfs/nfs_vnops.c
sys/vfs/nfs/nfsmount.h
sys/vfs/nfs/nfsnode.h

index cc401b7..ac1ae64 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_node.c  8.6 (Berkeley) 5/22/95
  * $FreeBSD: src/sys/nfs/nfs_node.c,v 1.36.2.3 2002/01/05 22:25:04 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_node.c,v 1.7 2003/08/07 21:17:42 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_node.c,v 1.8 2003/10/10 22:01:13 dillon Exp $
  */
 
 
@@ -53,8 +53,8 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 
 static vm_zone_t nfsnode_zone;
 static LIST_HEAD(nfsnodehashhead, nfsnode) *nfsnodehashtbl;
@@ -278,6 +278,14 @@ nfs_reclaim(ap)
        if (np->n_fhsize > NFS_SMALLFH) {
                FREE((caddr_t)np->n_fhp, M_NFSBIGFH);
        }
+       if (np->n_rucred) {
+               crfree(np->n_rucred);
+               np->n_rucred = NULL;
+       }
+       if (np->n_wucred) {
+               crfree(np->n_wucred);
+               np->n_wucred = NULL;
+       }
 
        cache_purge(vp);
        zfree(nfsnode_zone, vp->v_data);
index 6bd1154..9b5765b 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_nqlease.c       8.9 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/nfs/nfs_nqlease.c,v 1.50 2000/02/13 03:32:05 peter Exp $
- * $DragonFly: src/sys/vfs/nfs/Attic/nfs_nqlease.c,v 1.11 2003/09/03 14:30:57 hmp Exp $
+ * $DragonFly: src/sys/vfs/nfs/Attic/nfs_nqlease.c,v 1.12 2003/10/10 22:01:13 dillon Exp $
  */
 
 
@@ -73,8 +73,8 @@
 #include "nfsm_subs.h"
 #include "xdr_subs.h"
 #include "nqnfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 
 static MALLOC_DEFINE(M_NQMHOST, "NQNFS Host", "Nqnfs host address table");
 
@@ -872,7 +872,7 @@ nqnfs_getlease(struct vnode *vp, int rwflag, struct thread *td)
        *tl++ = txdr_unsigned(rwflag);
        *tl = txdr_unsigned(nmp->nm_leaseterm);
        reqtime = time_second;
-       nfsm_request(vp, NQNFSPROC_GETLEASE, td, NFSVPCRED(vp));
+       nfsm_request(vp, NQNFSPROC_GETLEASE, td, nfs_vpcred(vp, rwflag));
        np = VTONFS(vp);
        nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
        cachable = fxdr_unsigned(int, *tl++);
index 6677aad..75e21c7 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
  * $FreeBSD: src/sys/nfs/nfs_subs.c,v 1.90.2.2 2001/10/25 19:18:53 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_subs.c,v 1.9 2003/09/23 05:03:53 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_subs.c,v 1.10 2003/10/10 22:01:13 dillon Exp $
  */
 
 /*
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
+#include "nfsmount.h"
 #include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
-#include "nfsmount.h"
 #include "nqnfs.h"
 #include "nfsrtt.h"
 
index 043b69e..78257f9 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_vfsops.c        8.12 (Berkeley) 5/20/95
  * $FreeBSD: src/sys/nfs/nfs_vfsops.c,v 1.91.2.7 2003/01/27 20:04:08 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.8 2003/08/20 09:56:33 rob Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_vfsops.c,v 1.9 2003/10/10 22:01:13 dillon Exp $
  */
 
 #include "opt_bootp.h"
@@ -64,8 +64,8 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsdiskless.h"
@@ -333,7 +333,7 @@ nfs_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct thread *td)
        nfsstats.rpccnt[NFSPROC_FSINFO]++;
        nfsm_reqhead(vp, NFSPROC_FSINFO, NFSX_FH(1));
        nfsm_fhtom(vp, 1);
-       nfsm_request(vp, NFSPROC_FSINFO, td, NFSVPCRED(vp));
+       nfsm_request(vp, NFSPROC_FSINFO, td, nfs_vpcred(vp, ND_READ));
        nfsm_postop_attr(vp, retattr);
        if (!error) {
                nfsm_dissect(fsp, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
index 69e1c03..1fac976 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
  * $FreeBSD: src/sys/nfs/nfs_vnops.c,v 1.150.2.5 2001/12/20 19:56:28 dillon Exp $
- * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.13 2003/10/09 22:27:26 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfs_vnops.c,v 1.14 2003/10/10 22:01:13 dillon Exp $
  */
 
 
@@ -75,8 +75,8 @@
 #include "rpcv2.h"
 #include "nfsproto.h"
 #include "nfs.h"
-#include "nfsnode.h"
 #include "nfsmount.h"
+#include "nfsnode.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nqnfs.h"
@@ -397,7 +397,6 @@ nfs_access(ap)
                                }
                        }
                }
-               return (error);
        } else {
                if ((error = nfsspec_access(ap)) != 0)
                        return (error);
@@ -425,22 +424,41 @@ nfs_access(ap)
                        auio.uio_rw = UIO_READ;
                        auio.uio_td = ap->a_td;
 
-                       if (vp->v_type == VREG)
+                       if (vp->v_type == VREG) {
                                error = nfs_readrpc(vp, &auio);
-                       else if (vp->v_type == VDIR) {
+                       else if (vp->v_type == VDIR) {
                                char* bp;
                                bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK);
                                aiov.iov_base = bp;
                                aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ;
                                error = nfs_readdirrpc(vp, &auio);
                                free(bp, M_TEMP);
-                       } else if (vp->v_type == VLNK)
+                       } else if (vp->v_type == VLNK) {
                                error = nfs_readlinkrpc(vp, &auio);
-                       else
+                       } else {
                                error = EACCES;
+                       }
                }
-               return (error);
        }
+       /*
+        * [re]record creds for reading and/or writing if access
+        * was granted.
+        */
+       if (error == 0) {
+               if ((ap->a_mode & VREAD) && ap->a_cred != np->n_rucred) {
+                       crhold(ap->a_cred);
+                       if (np->n_rucred)
+                               crfree(np->n_rucred);
+                       np->n_rucred = ap->a_cred;
+               }
+               if ((ap->a_mode & VWRITE) && ap->a_cred != np->n_wucred) {
+                       crhold(ap->a_cred);
+                       if (np->n_wucred)
+                               crfree(np->n_wucred);
+                       np->n_wucred = ap->a_cred;
+               }
+       }
+       return(error);
 }
 
 /*
@@ -637,7 +655,7 @@ nfs_getattr(ap)
 
        if (v3 && nfsaccess_cache_timeout > 0) {
                nfsstats.accesscache_misses++;
-               nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_td, NFSVPCRED(vp));
+               nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_td, nfs_vpcred(vp, ND_CHECK));
                if (nfs_getattrcache(vp, ap->a_vap) == 0)
                        return (0);
        }
@@ -645,7 +663,7 @@ nfs_getattr(ap)
        nfsstats.rpccnt[NFSPROC_GETATTR]++;
        nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
        nfsm_fhtom(vp, v3);
-       nfsm_request(vp, NFSPROC_GETATTR, ap->a_td, NFSVPCRED(vp));
+       nfsm_request(vp, NFSPROC_GETATTR, ap->a_td, nfs_vpcred(vp, ND_CHECK));
        if (!error) {
                nfsm_loadattr(vp, ap->a_vap);
        }
@@ -1056,7 +1074,7 @@ nfs_readlinkrpc(struct vnode *vp, struct uio *uiop)
        nfsstats.rpccnt[NFSPROC_READLINK]++;
        nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
        nfsm_fhtom(vp, v3);
-       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_td, NFSVPCRED(vp));
+       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_td, nfs_vpcred(vp, ND_CHECK));
        if (v3)
                nfsm_postop_attr(vp, attrflag);
        if (!error) {
@@ -1109,7 +1127,7 @@ nfs_readrpc(struct vnode *vp, struct uio *uiop)
                        *tl++ = txdr_unsigned(len);
                        *tl = 0;
                }
-               nfsm_request(vp, NFSPROC_READ, uiop->uio_td, NFSVPCRED(vp));
+               nfsm_request(vp, NFSPROC_READ, uiop->uio_td, nfs_vpcred(vp, ND_READ));
                if (v3) {
                        nfsm_postop_attr(vp, attrflag);
                        if (error) {
@@ -1188,7 +1206,7 @@ nfs_writerpc(vp, uiop, iomode, must_commit)
                        *tl = x;        /* size of this write */
                }
                nfsm_uiotom(uiop, len);
-               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_td, NFSVPCRED(vp));
+               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_td, nfs_vpcred(vp, ND_WRITE));
                if (v3) {
                        wccflag = NFSV3_WCCCHK;
                        nfsm_wcc_data(vp, wccflag);
@@ -1467,6 +1485,16 @@ again:
        if (!error) {
                if (cnp->cn_flags & CNP_MAKEENTRY)
                        cache_enter(dvp, NCPNULL, newvp, cnp);
+               /*
+                * The new np may have enough info for access
+                * checks, make sure rucred and wucred are
+                * initialized for read and write rpc's.
+                */
+               np = VTONFS(newvp);
+               if (np->n_rucred == NULL)
+                       np->n_rucred = crhold(cnp->cn_cred);
+               if (np->n_wucred == NULL)
+                       np->n_wucred = crhold(cnp->cn_cred);
                *ap->a_vpp = newvp;
        }
        VTONFS(dvp)->n_flag |= NMODIFIED;
@@ -2124,7 +2152,7 @@ nfs_readdirrpc(struct vnode *vp, struct uio *uiop)
                        *tl++ = cookie.nfsuquad[0];
                }
                *tl = txdr_unsigned(nmp->nm_readdirsize);
-               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_td, NFSVPCRED(vp));
+               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_td, nfs_vpcred(vp, ND_READ));
                if (v3) {
                        nfsm_postop_attr(vp, attrflag);
                        if (!error) {
@@ -2311,7 +2339,7 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop)
                *tl++ = dnp->n_cookieverf.nfsuquad[1];
                *tl++ = txdr_unsigned(nmp->nm_readdirsize);
                *tl = txdr_unsigned(nmp->nm_rsize);
-               nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_td, NFSVPCRED(vp));
+               nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_td, nfs_vpcred(vp, ND_READ));
                nfsm_postop_attr(vp, attrflag);
                if (error) {
                        m_freem(mrep);
@@ -2642,7 +2670,7 @@ nfs_commit(struct vnode *vp, u_quad_t offset, int cnt, struct thread *td)
        txdr_hyper(offset, tl);
        tl += 2;
        *tl = txdr_unsigned(cnt);
-       nfsm_request(vp, NFSPROC_COMMIT, td, NFSVPCRED(vp));
+       nfsm_request(vp, NFSPROC_COMMIT, td, nfs_vpcred(vp, ND_WRITE));
        nfsm_wcc_data(vp, wccflag);
        if (!error) {
                nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF);
@@ -3267,7 +3295,7 @@ nfsspec_close(ap)
                                vattr.va_atime = np->n_atim;
                        if (np->n_flag & NUPD)
                                vattr.va_mtime = np->n_mtim;
-                       (void)VOP_SETATTR(vp, &vattr, NFSVPCRED(vp), ap->a_td);
+                       (void)VOP_SETATTR(vp, &vattr, nfs_vpcred(vp, ND_WRITE), ap->a_td);
                }
        }
        return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
@@ -3349,7 +3377,7 @@ nfsfifo_close(ap)
                                vattr.va_atime = np->n_atim;
                        if (np->n_flag & NUPD)
                                vattr.va_mtime = np->n_mtim;
-                       (void)VOP_SETATTR(vp, &vattr, NFSVPCRED(vp), ap->a_td);
+                       (void)VOP_SETATTR(vp, &vattr, nfs_vpcred(vp, ND_WRITE), ap->a_td);
                }
        }
        return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
index 38514ae..071f818 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfsmount.h  8.3 (Berkeley) 3/30/95
  * $FreeBSD: src/sys/nfs/nfsmount.h,v 1.17 1999/12/29 04:54:54 peter Exp $
- * $DragonFly: src/sys/vfs/nfs/nfsmount.h,v 1.3 2003/06/26 05:55:18 dillon Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfsmount.h,v 1.4 2003/10/10 22:01:13 dillon Exp $
  */
 
 
@@ -103,7 +103,6 @@ struct      nfsmount {
  * Convert mount ptr to nfsmount ptr.
  */
 #define VFSTONFS(mp)   ((struct nfsmount *)((mp)->mnt_data))
-#define NFSVPCRED(vp)  (VFSTONFS((vp)->v_mount)->nm_cred)
 extern void nfs_free_mount(struct nfsmount *nmp);
 
 #endif
index 2829077..be78c77 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     @(#)nfsnode.h   8.9 (Berkeley) 5/14/95
  * $FreeBSD: src/sys/nfs/nfsnode.h,v 1.32.2.1 2001/06/26 04:20:11 bp Exp $
- * $DragonFly: src/sys/vfs/nfs/nfsnode.h,v 1.5 2003/08/20 09:56:33 rob Exp $
+ * $DragonFly: src/sys/vfs/nfs/nfsnode.h,v 1.6 2003/10/10 22:01:13 dillon Exp $
  */
 
 
@@ -75,16 +75,19 @@ struct nfsdmap {
 
 /*
  * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
- * is purely coincidental.
- * There is a unique nfsnode allocated for each active file,
- * each current directory, each mounted-on file, text file, and the root.
+ * is purely coincidental.  There is a unique nfsnode allocated for
+ * each active file, each current directory, each mounted-on file,
+ * text file, and the root.
+ *
  * An nfsnode is 'named' by its file handle. (nget/nfs_node.c)
- * If this structure exceeds 256 bytes (it is currently 256 using 4.4BSD-Lite
- * type definitions), file handles of > 32 bytes should probably be split out
- * into a separate MALLOC()'d data structure. (Reduce the size of nfsfh_t by
- * changing the definition in nfsproto.h of NFS_SMALLFH.)
- * NB: Hopefully the current order of the fields is such that everything will
- *     be well aligned and, therefore, tightly packed.
+ *
+ * File handles are accessed via n_fhp, which will point to n_fh if the
+ * file handle is small enough (<= NFS_SMALLFH).  Otherwise the file handle 
+ * will be allocated.
+ *
+ * DragonFly does not pass ucreds to read and write operations, since such
+ * operations are not possible unless the ucred has already been validated.
+ * Validating ucreds are stored in nfsnode to pass on to NFS read/write RPCs.
  */
 struct nfsnode {
        struct lock             n_lock;
@@ -102,6 +105,8 @@ struct nfsnode {
        time_t                  n_ctime;        /* Prev create time. */
        time_t                  n_expiry;       /* Lease expiry time */
        nfsfh_t                 *n_fhp;         /* NFS File Handle */
+       struct ucred            *n_rucred;
+       struct ucred            *n_wucred;
        struct vnode            *n_vnode;       /* associated vnode */
        struct lockf            *n_lockf;       /* Locking record of file */
        int                     n_error;        /* Save write error value */
@@ -185,6 +190,19 @@ nfs_rsunlock(struct nfsnode *np, struct thread *td)
        (void)lockmgr(&np->n_rslock, LK_RELEASE, NULL, td);
 }
 
+static __inline
+struct ucred *
+nfs_vpcred(struct vnode *vp, int ndflag)
+{
+       struct nfsnode *np = VTONFS(vp);
+
+       if (np && (ndflag & ND_WRITE) && np->n_wucred)
+               return(np->n_wucred);
+       if (np && (ndflag & ND_READ) && np->n_rucred)
+               return(np->n_rucred);
+       return(VFSTONFS((vp)->v_mount)->nm_cred);
+}
+
 extern vop_t   **fifo_nfsv2nodeop_p;
 extern vop_t   **nfsv2_vnodeop_p;
 extern vop_t   **spec_nfsv2nodeop_p;