- if ((nfsmode & NFSV3ACCESS_READ) &&
- nfsrv_access(vp, VREAD, cred, rdonly, procp, 0))
- nfsmode &= ~NFSV3ACCESS_READ;
- if (vp->v_type == VDIR)
- testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
- NFSV3ACCESS_DELETE);
- else
- testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
- if ((nfsmode & testmode) &&
- nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0))
- nfsmode &= ~testmode;
- if (vp->v_type == VDIR)
- testmode = NFSV3ACCESS_LOOKUP;
- else
- testmode = NFSV3ACCESS_EXECUTE;
- if ((nfsmode & testmode) &&
- nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0))
- nfsmode &= ~testmode;
- getret = VOP_GETATTR(vp, vap, cred, procp);
- vput(vp);
+
+ context.vc_proc = procp;
+ context.vc_ucred = nfsd->nd_cr;
+
+ /*
+ * Each NFS mode bit is tested separately.
+ *
+ * XXX this code is nominally correct, but returns a pessimistic
+ * rather than optimistic result. It will be necessary to add
+ * an NFS-specific interface to the vnode_authorize code to
+ * obtain good performance in the optimistic mode.
+ */
+ if (nfsmode & NFSV3ACCESS_READ) {
+ if (vnode_isdir(vp)) {
+ testaction =
+ KAUTH_VNODE_LIST_DIRECTORY |
+ KAUTH_VNODE_READ_EXTATTRIBUTES;
+ } else {
+ testaction =
+ KAUTH_VNODE_READ_DATA |
+ KAUTH_VNODE_READ_EXTATTRIBUTES;
+ }
+ if (nfsrv_authorize(vp, NULL, testaction, &context, nxo, 0))
+ nfsmode &= ~NFSV3ACCESS_READ;
+ }
+ if ((nfsmode & NFSV3ACCESS_LOOKUP) &&
+ (!vnode_isdir(vp) ||
+ nfsrv_authorize(vp, NULL, KAUTH_VNODE_SEARCH, &context, nxo, 0)))
+ nfsmode &= ~NFSV3ACCESS_LOOKUP;
+ if (nfsmode & NFSV3ACCESS_MODIFY) {
+ if (vnode_isdir(vp)) {
+ testaction =
+ KAUTH_VNODE_ADD_FILE |
+ KAUTH_VNODE_ADD_SUBDIRECTORY |
+ KAUTH_VNODE_DELETE_CHILD;
+ } else {
+ testaction =
+ KAUTH_VNODE_WRITE_DATA |
+ KAUTH_VNODE_WRITE_ATTRIBUTES |
+ KAUTH_VNODE_WRITE_EXTATTRIBUTES |
+ KAUTH_VNODE_WRITE_SECURITY;
+ }
+ if (nfsrv_authorize(vp, NULL, testaction, &context, nxo, 0))
+ nfsmode &= ~NFSV3ACCESS_MODIFY;
+ }
+ if (nfsmode & NFSV3ACCESS_EXTEND) {
+ if (vnode_isdir(vp)) {
+ testaction =
+ KAUTH_VNODE_ADD_FILE |
+ KAUTH_VNODE_ADD_SUBDIRECTORY;
+ } else {
+ testaction =
+ KAUTH_VNODE_WRITE_DATA |
+ KAUTH_VNODE_APPEND_DATA;
+ }
+ if (nfsrv_authorize(vp, NULL, testaction, &context, nxo, 0))
+ nfsmode &= ~NFSV3ACCESS_EXTEND;
+ }
+
+ /*
+ * Note concerning NFSV3ACCESS_DELETE:
+ * For hard links, the answer may be wrong if the vnode
+ * has multiple parents with different permissions.
+ * Also, some clients (e.g. MacOSX 10.3) may incorrectly
+ * interpret the missing/cleared DELETE bit.
+ * So we'll just leave the DELETE bit alone. At worst,
+ * we're telling the client it might be able to do
+ * something it really can't.
+ */
+
+ if ((nfsmode & NFSV3ACCESS_EXECUTE) &&
+ (vnode_isdir(vp) ||
+ nfsrv_authorize(vp, NULL, KAUTH_VNODE_EXECUTE, &context, nxo, 0)))
+ nfsmode &= ~NFSV3ACCESS_EXECUTE;
+
+ nfsm_srv_vattr_init(vap, 1);
+ getret = vnode_getattr(vp, vap, &context);
+ vnode_put(vp);