Add kernel-layer support for chflags checks, remove (most) from the VFS layer.
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 May 2009 02:14:31 +0000 (19:14 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 6 May 2009 02:14:31 +0000 (19:14 -0700)
Give nlookup() and nlookup_va() the tools to do nearly all chflags related
activities.  Here are the rules:

Immutable (uchg, schg)

    If set on a directory no files associated with the directory may
    be created, deleted, linked, or renamed.  In addition, any files open()ed
    via the directory will be immutable whether they are flagged that
    way or not.

    If set on a file or directory the file or directory may not be
    written to, chmodded, chowned, chgrped, or renamed.  The file can
    still be hardlinked and the file/directory can still be chflagged.
    If you do not wish the file to be linkable then set the immutable bit
    on all directories containing a link of the file.  Once you form
    this closure no further links will be possible.

    NOTE ON REASONING:  Security scripts should check link counts anyway,
    depending on a file flag which can be changed as a replacement for
    checking the link count is stupid.  If you are secure then your closures
    will hold.  If you aren't then nothing will save you.

    This feature is not recursive.  If the directory contains
    subdirectories they must be flagged immutable as well.

Undeletable (uunlnk, sunlnk)

    If set on a file or directory that file or directory cannot be removed
    or renamed.  The file can still otherwise be manipulated, linked, and
    so forth.  However, it should be noted that any hardlinks you create
    will also not be deletable :-)

    If set on a directory this flag has no effect on the contents
    of the directory (yet).  See APPEND-ONLY on directories for what
    you want.

Append-only (uappnd/sappnd)

    If set on a directory no file within the directory may be deleted or
    renamed.  However, new files may be created in the directory and
    the files in the directory can be modified or hardlinked without
    restriction.

    If set on a file the file cannot be truncated, random-written, or
    deleted.  It CAN be chmoded, chowned, renamed, and appended to
    with O_APPEND etc.

    If you do not wish the file to be renameable then you must also
    set the Undeletable flag.  Setting the append-only flag will ensure
    that the file doesn't disappear from the filesystem, but does not
    prevent it from being moved about the filesystem.

Security fix - futimes()

    futimes() could be called on any open descriptor.  Restrict
    it to just those files you own or have write permission on.

Security fix - Hardlinks

    Users can no longer hardlink foreign-owned files which they do not
    have write access to.  The user must now have write permission on
    the file being hardlinked or the user must own the file, or be root.

Security fix - fcntl()

    fcntl() can no longer be used to turn of O_APPEND mode if the file
    was flagged append-only.

NOTE - DIFFERENCES WITH FREEBSD

    * Append-only on directories

    * Immutable on directories to control set-in-stone & hardlinking

    * Immutable files can be hardlinked on DragonFly, not on FreeBSD.

    * User must be the owner of the file or have write access to the
      file being hardlinked.

19 files changed:
sys/emulation/linux/linux_misc.c
sys/kern/kern_descrip.c
sys/kern/vfs_helper.c
sys/kern/vfs_nlookup.c
sys/kern/vfs_syscalls.c
sys/kern/vfs_vnops.c
sys/sys/fcntl.h
sys/sys/nlookup.h
sys/sys/vnode.h
sys/vfs/gnu/ext2fs/ext2_vnops.c
sys/vfs/hpfs/hpfs_vnops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/nfs/nfs_serv.c
sys/vfs/nfs/nfs_subs.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/nwfs/nwfs_vnops.c
sys/vfs/smbfs/smbfs_vnops.c
sys/vfs/udf/udf_vnops.c
sys/vfs/ufs/ufs_vnops.c

index a9c7960..8d6927b 100644 (file)
@@ -264,6 +264,7 @@ sys_linux_uselib(struct linux_uselib_args *args)
        vp = NULL;
 
        error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
+       nd.nl_flags |= NLC_EXEC;
        if (error == 0)
                error = nlookup(&nd);
        if (error == 0)
@@ -298,11 +299,6 @@ sys_linux_uselib(struct linux_uselib_args *args)
                goto cleanup;
        }
 
-       /* Can we access it? */
-       error = VOP_ACCESS(vp, VEXEC, p->p_ucred);
-       if (error)
-               goto cleanup;
-
        error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL);
        if (error)
                goto cleanup;
index a71e934..1d79a91 100644 (file)
@@ -227,6 +227,7 @@ kern_fcntl(int fd, int cmd, union fcntl_dat *dat, struct ucred *cred)
        struct vnode *vp;
        u_int newmin;
        u_int oflags;
+       u_int nflags;
        int tmp, error, flg = F_POSIX;
 
        KKASSERT(p);
@@ -269,16 +270,19 @@ kern_fcntl(int fd, int cmd, union fcntl_dat *dat, struct ucred *cred)
                break;
 
        case F_SETFL:
-               oflags = fp->f_flag & FCNTLFLAGS;
-               fp->f_flag &= ~FCNTLFLAGS;
-               fp->f_flag |= FFLAGS(dat->fc_flags & ~O_ACCMODE) & FCNTLFLAGS;
+               oflags = fp->f_flag;
+               nflags = FFLAGS(dat->fc_flags & ~O_ACCMODE) & FCNTLFLAGS;
+               nflags |= oflags & ~FCNTLFLAGS;
+
                error = 0;
-               if ((fp->f_flag ^ oflags) & FASYNC) {
+               if (((nflags ^ oflags) & O_APPEND) && (oflags & FAPPENDONLY))
+                       error = EINVAL;
+               if (error == 0 && ((nflags ^ oflags) & FASYNC)) {
                        tmp = fp->f_flag & FASYNC;
                        error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, cred);
                }
-               if (error)
-                       fp->f_flag = (fp->f_flag & ~FCNTLFLAGS) | oflags;
+               if (error == 0)
+                       fp->f_flag = nflags;
                break;
 
        case F_GETOWN:
index 0ea69e5..531fd3e 100644 (file)
@@ -110,8 +110,6 @@ vop_helper_access(struct vop_access_args *ap, uid_t ino_uid, gid_t ino_gid,
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ino_uid) {
-               if (mode & VOWN)
-                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 3efa97f..ab783b8 100644 (file)
@@ -70,8 +70,6 @@
 #include <sys/ktrace.h>
 #endif
 
-static int naccess_va(struct vattr *va, int vmode, struct ucred *cred);
-
 /*
  * Initialize a nlookup() structure, early error return for copyin faults
  * or a degenerate empty string (which is not allowed).
@@ -283,10 +281,9 @@ nlookup_simple(const char *str, enum uio_seg seg,
  * and an error code of 0 will be returned for a non-existant
  * target (not ENOENT).
  *
- * If NLC_RENAME is set the last directory mut allow node deletion,
+ * If NLC_RENAME_DST is set the last directory mut allow node deletion,
  * plus the sticky check is made, and an error code of 0 will be returned
- * for a non-existant target (not ENOENT).  NLC_RENAME is set used for
- * the rename target.
+ * for a non-existant target (not ENOENT).
  *
  * If NLC_DELETE is set the last directory mut allow node deletion,
  * plus the sticky check is made.
@@ -300,12 +297,14 @@ nlookup(struct nlookupdata *nd)
 {
     struct nlcomponent nlc;
     struct nchandle nch;
+    struct nchandle par;
     struct mount *mp;
     int wasdotordotdot;
     char *ptr;
     char *xptr;
     int error;
     int len;
+    int dflags;
 
 #ifdef KTRACE
     if (KTRPOINT(nd->nl_td, KTR_NAMEI))
@@ -371,7 +370,8 @@ nlookup(struct nlookupdata *nd)
        /*
         * Check directory search permissions.
         */
-       if ((error = naccess(&nd->nl_nch, VEXEC, nd->nl_cred, NULL)) != 0)
+       dflags = 0;
+       if ((error = naccess(&nd->nl_nch, NLC_EXEC, nd->nl_cred, &dflags)) != 0)
            break;
 
        /*
@@ -390,6 +390,10 @@ nlookup(struct nlookupdata *nd)
         * When handling ".." we have to detect a traversal back through a
         * mount point.   If we are at the root, ".." just returns the root.
         *
+        * When handling "." or ".." we also have to recalculate dflags
+        * since our dflags will be for some sub-directory instead of the
+        * parent dir.
+        *
         * This subsection returns a locked, refd 'nch' unless it errors out.
         * The namecache topology is not allowed to be disconnected, so 
         * encountering a NULL parent will generate EINVAL.  This typically
@@ -431,6 +435,23 @@ nlookup(struct nlookupdata *nd)
            }
            wasdotordotdot = 0;
        }
+
+       /*
+        * If the last component was "." or ".." our dflags no longer
+        * represents the parent directory and we have to explicitly
+        * look it up.
+        */
+       if (wasdotordotdot && error == 0) {
+           dflags = 0;
+           if ((par.ncp = nch.ncp->nc_parent) != NULL) {
+               par.mount = nch.mount;
+               cache_hold(&par);
+               dflags = 0;
+               error = naccess(&par, 0, nd->nl_cred, &dflags);
+               cache_drop(&par);
+           }
+       }
+
        /*
         * [end of subsection] ncp is locked and ref'd.  nd->nl_nch is ref'd
         */
@@ -455,9 +476,6 @@ nlookup(struct nlookupdata *nd)
         * requested.  Note that ncp->nc_error is left as ENOENT in that
         * case, which we check later on.
         *
-        * NOTE: For NLC_RENAME in the ENOENT case we do a VCREATE test,
-        *       same as for NLC_CREATE.
-        *
         * Also handle invalid '.' or '..' components terminating a path
         * for a create/rename/delete.  The standard requires this and pax
         * pretty stupidly depends on it.
@@ -465,14 +483,19 @@ nlookup(struct nlookupdata *nd)
        for (xptr = ptr; *xptr == '/'; ++xptr)
                ;
        if (*xptr == 0) {
-           if (error == ENOENT && (nd->nl_flags & (NLC_CREATE | NLC_RENAME))) {
-               if (nd->nl_flags & NLC_NFS_RDONLY)
+           if (error == ENOENT &&
+               (nd->nl_flags & (NLC_CREATE | NLC_RENAME_DST))
+           ) {
+               if (nd->nl_flags & NLC_NFS_RDONLY) {
                        error = EROFS;
-               else
-                       error = naccess(&nch, VCREATE, nd->nl_cred, NULL);
+               } else {
+                       error = naccess(&nch, nd->nl_flags | dflags,
+                                       nd->nl_cred, NULL);
+               }
            }
            if (error == 0 && wasdotordotdot &&
-               (nd->nl_flags & (NLC_CREATE | NLC_RENAME | NLC_DELETE))) {
+               (nd->nl_flags & (NLC_CREATE | NLC_DELETE |
+                                NLC_RENAME_SRC | NLC_RENAME_DST))) {
                error = EINVAL;
            }
        }
@@ -599,17 +622,17 @@ nlookup(struct nlookupdata *nd)
        /*
         * Successful lookup of last element.
         *
-        * Check directory permissions if a deletion or rename (target)
-        * is specified.  This also handles the sticky test.
+        * Check permissions if the target exists.  If the target does not
+        * exist directory permissions were already tested in the early
+        * completion code above.
         *
-        * We already checked permissions for creates in the early
-        * termination code above.
+        * nd->nl_flags will be adjusted on return with NLC_APPENDONLY
+        * if the file is marked append-only, and NLC_STICKY if the directory
+        * containing the file is sticky.
         */
-       if (*ptr == 0 && (nd->nl_flags & (NLC_DELETE | NLC_RENAME))) {
-           if (nd->nl_flags & NLC_DELETE)
-               error = naccess(&nch, VDELETE, nd->nl_cred, NULL);
-           else
-               error = naccess(&nch, VRENAME, nd->nl_cred, NULL);
+       if (nch.ncp->nc_vp && (nd->nl_flags & NLC_ALLCHKS)) {
+           error = naccess(&nch, nd->nl_flags | dflags,
+                           nd->nl_cred, NULL);
            if (error) {
                cache_put(&nch);
                break;
@@ -617,9 +640,7 @@ nlookup(struct nlookupdata *nd)
        }
 
        /*
-        * Termination: no more elements.  If NLC_CREATE was set the
-        * ncp may represent a negative hit (ncp->nc_error will be ENOENT),
-        * but we still return an error code of 0.
+        * Termination: no more elements.
         *
         * If NLC_REFDVP is set acquire a referenced parent dvp.
         */
@@ -637,6 +658,12 @@ nlookup(struct nlookupdata *nd)
        error = 0;
        break;
     }
+
+    /*
+     * NOTE: If NLC_CREATE was set the ncp may represent a negative hit
+     * (ncp->nc_error will be ENOENT), but we will still return an error
+     * code of 0.
+     */
     return(error);
 }
 
@@ -728,26 +755,27 @@ fail:
 /*
  * Check access [XXX cache vattr!] [XXX quota]
  *
- * Generally check the V* access bits from sys/vnode.h.  All specified bits
- * must pass for this function to return 0.
+ * Generally check the NLC_* access bits.   All specified bits must pass
+ * for this function to return 0.
  *
- * The file does not have to exist when checking VCREATE or VRENAME access.
+ * The file does not have to exist when checking NLC_CREATE or NLC_RENAME_DST
+ * access, otherwise it must exist.  No error is returned in this case.
  *
- * The file must not exist if VEXCL is specified.
+ * The file must not exist if NLC_EXCL is specified.
  *
- * Directory permissions in general are tested for VCREATE if the file
- * does not exist, VDELETE if the file does exist, and VRENAME whether
- * the file exists or not.
+ * Directory permissions in general are tested for NLC_CREATE if the file
+ * does not exist, NLC_DELETE if the file does exist, and NLC_RENAME_DST
+ * whether the file exists or not.
  *
- * The directory sticky bit is tested for VDELETE and VRENAME.  NOTE: For
- * VRENAME we only care if the target exists.
+ * The directory sticky bit is tested for NLC_DELETE and NLC_RENAME_DST,
+ * the latter is only tested if the target exists.
  *
  * The passed ncp may or may not be locked.  The caller should use a
- * locked ncp on leaf lookups, especially for VCREATE, VRENAME, VDELETE,
- * and VEXCL checks.
+ * locked ncp on leaf lookups, especially for NLC_CREATE, NLC_RENAME_DST,
+ * NLC_DELETE, and NLC_EXCL checks.
  */
 int
-naccess(struct nchandle *nch, int vmode, struct ucred *cred, int *stickyp)
+naccess(struct nchandle *nch, int nflags, struct ucred *cred, int *nflagsp)
 {
     struct nchandle par;
     struct vnode *vp;
@@ -761,62 +789,114 @@ naccess(struct nchandle *nch, int vmode, struct ucred *cred, int *stickyp)
        cache_unlock(nch);
     }
     error = nch->ncp->nc_error;
-    sticky = 0;
 
     /*
-     * Directory permissions and VEXCL checks.  Do a precursor conditional
-     * to reduce overhead since most access checks are for read-only.
+     * Directory permissions checks.  Silently ignore ENOENT if these
+     * tests pass.  It isn't an error.
      */
-    if (vmode & (VDELETE|VRENAME|VCREATE|VEXCL)) {
-       if (((vmode & VCREATE) && nch->ncp->nc_vp == NULL) ||
-           ((vmode & VDELETE) && nch->ncp->nc_vp != NULL) ||
-           (vmode & VRENAME)
+    if (nflags & (NLC_CREATE | NLC_DELETE | NLC_RENAME_SRC | NLC_RENAME_DST)) {
+       if (((nflags & NLC_CREATE) && nch->ncp->nc_vp == NULL) ||
+           ((nflags & NLC_DELETE) && nch->ncp->nc_vp != NULL) ||
+           ((nflags & NLC_RENAME_SRC) && nch->ncp->nc_vp != NULL) ||
+           (nflags & NLC_RENAME_DST)
        ) {
            if ((par.ncp = nch->ncp->nc_parent) == NULL) {
                if (error != EAGAIN)
                        error = EINVAL;
-           } else {
+           } else if (error == 0 || error == ENOENT) {
                par.mount = nch->mount;
                cache_hold(&par);
-               error = naccess(&par, VWRITE, cred, &sticky);
-               if ((vmode & (VDELETE | VRENAME)) && sticky)
-                   vmode |= VSVTX;
+               sticky = 0;
+               error = naccess(&par, NLC_WRITE, cred, NULL);
                cache_drop(&par);
            }
        }
-       if ((vmode & VEXCL) && nch->ncp->nc_vp != NULL)
-           error = EEXIST;
     }
+
+    /*
+     * NLC_EXCL check.  Target file must not exist.
+     */
+    if (error == 0 && (nflags & NLC_EXCL) && nch->ncp->nc_vp != NULL)
+       error = EEXIST;
+
+    /*
+     * Get the vnode attributes so we can do the rest of our checks.
+     *
+     * NOTE: We only call naccess_va() if the target exists.
+     */
     if (error == 0) {
        error = cache_vget(nch, cred, LK_SHARED, &vp);
        if (error == ENOENT) {
-           if (vmode & (VCREATE | VRENAME))
+           /*
+            * Silently zero-out ENOENT if creating or renaming
+            * (rename target).  It isn't an error.
+            */
+           if (nflags & (NLC_CREATE | NLC_RENAME_DST))
                error = 0;
        } else if (error == 0) {
-           /* XXX cache the va in the namecache or in the vnode */
-           if ((error = VOP_GETATTR(vp, &va)) == 0) {
-               if ((vmode & VWRITE) && vp->v_mount) {
-                   if (vp->v_mount->mnt_flag & MNT_RDONLY)
-                       error = EROFS;
+           /*
+            * Get the vnode attributes and check for illegal O_TRUNC
+            * requests and read-only mounts.
+            *
+            * NOTE: You can still open devices on read-only mounts for
+            *       writing.
+            *
+            * NOTE: creates/deletes/renames are handled by the NLC_WRITE
+            *       check on the parent directory above.
+            *
+            * XXX cache the va in the namecache or in the vnode
+            */
+           error = VOP_GETATTR(vp, &va);
+           if (error == 0 && (nflags & NLC_TRUNCATE)) {
+               switch(va.va_type) {
+               case VREG:
+               case VDATABASE:
+               case VCHR:
+               case VBLK:
+                   break;
+               default:
+                   error = EINVAL;
+                   break;
+               }
+           }
+           if (error == 0 && (nflags & NLC_WRITE) && vp->v_mount &&
+               (vp->v_mount->mnt_flag & MNT_RDONLY)
+           ) {
+               switch(va.va_type) {
+               case VDIR:
+               case VLNK:
+               case VREG:
+               case VDATABASE:
+                   error = EROFS;
+                   break;
+               default:
+                   break;
                }
            }
            vput(vp);
 
+           /*
+            * Check permissions based on file attributes.  The passed
+            * flags (*nflagsp) are modified with feedback based on
+            * special attributes and requirements.
+            */
            if (error == 0) {
                /*
-                * Set the returned (*stickyp) if VSVTX is set and the uid
-                * is not the owner of the directory.  The caller uses this
-                * disallow deletions of files not owned by the user if the
-                * user also does not own the directory and the sticky bit
-                * is set on the directory.  Weird, I know.
+                * Adjust the returned (*nflagsp) if non-NULL.
                 */
-               if (stickyp && va.va_uid != cred->cr_uid)
-                   *stickyp = (va.va_mode & VSVTX);
+               if (nflagsp) {
+                   if ((va.va_mode & VSVTX) && va.va_uid != cred->cr_uid)
+                       *nflagsp |= NLC_STICKY;
+                   if (va.va_flags & APPEND)
+                       *nflagsp |= NLC_APPENDONLY;
+                   if (va.va_flags & IMMUTABLE)
+                       *nflagsp |= NLC_IMMUTABLE;
+               }
 
                /*
                 * Process general access.
                 */
-               error = naccess_va(&va, vmode, cred);
+               error = naccess_va(&va, nflags, cred);
            }
        }
     }
@@ -826,20 +906,88 @@ naccess(struct nchandle *nch, int vmode, struct ucred *cred, int *stickyp)
 /*
  * Check the requested access against the given vattr using cred.
  */
-static
 int
-naccess_va(struct vattr *va, int vmode, struct ucred *cred)
+naccess_va(struct vattr *va, int nflags, struct ucred *cred)
 {
     int i;
+    int vmode;
 
     /*
-     * Test the immutable bit for files, directories, and softlinks.
+     * Test the immutable bit.  Creations, deletions, renames (source
+     * or destination) are not allowed.  chown/chmod/other is also not
+     * allowed but is handled by SETATTR.  Hardlinks to the immutable
+     * file are allowed.
+     *
+     * If the directory is set to immutable then creations, deletions,
+     * renames (source or dest) and hardlinks to files within the directory
+     * are not allowed, and regular files opened through the directory may
+     * not be written to or truncated (unless a special device).
      *
-     * NOTE: Only called for VRENAME if the target exists.
+     * NOTE!  New hardlinks to immutable files work but new hardlinks to
+     * files, immutable or not, sitting inside an immutable directory are
+     * not allowed.  As always if the file is hardlinked via some other
+     * path additional hardlinks may be possible even if the file is marked
+     * immutable.  The sysop needs to create a closure by checking the hard
+     * link count.  Once closure is achieved you are good, and security
+     * scripts should check link counts anyway.
+     *
+     * Writes and truncations are only allowed on special devices.
      */
-    if (vmode & (VWRITE|VDELETE|VRENAME)) {
-       if (va->va_type == VDIR || va->va_type == VLNK || va->va_type == VREG) {
-           if (va->va_flags & IMMUTABLE)
+    if ((va->va_flags & IMMUTABLE) || (nflags & NLC_IMMUTABLE)) {
+       if ((nflags & NLC_IMMUTABLE) && (nflags & NLC_HLINK))
+           return (EPERM);
+       if (nflags & (NLC_CREATE | NLC_DELETE |
+                     NLC_RENAME_SRC | NLC_RENAME_DST)) {
+           return (EPERM);
+       }
+       if (nflags & (NLC_WRITE | NLC_TRUNCATE)) {
+           switch(va->va_type) {
+           case VDIR:
+           case VLNK:
+           case VREG:
+           case VDATABASE:
+               return (EPERM);
+           default:
+               break;
+           }
+       }
+    }
+
+    /*
+     * Test the no-unlink and append-only bits for opens, rename targets,
+     * and deletions.  These bits are not tested for creations or
+     * rename sources.
+     *
+     * Unlike FreeBSD we allow a file with APPEND set to be renamed.
+     * If you do not wish this you must also set NOUNLINK.
+     *
+     * If the governing directory is marked APPEND-only it implies
+     * NOUNLINK for all entries in the directory.
+     */
+    if (((va->va_flags & NOUNLINK) || (nflags & NLC_APPENDONLY)) &&
+       (nflags & (NLC_DELETE | NLC_RENAME_SRC | NLC_RENAME_DST))
+    ) {
+       return (EPERM);
+    }
+
+    /*
+     * A file marked append-only may not be deleted but can be renamed.
+     */
+    if ((va->va_flags & APPEND) &&
+       (nflags & (NLC_DELETE | NLC_RENAME_DST))
+    ) {
+       return (EPERM);
+    }
+
+    /*
+     * A file marked append-only which is opened for writing must also
+     * be opened O_APPEND.
+     */
+    if ((va->va_flags & APPEND) && (nflags & (NLC_OPEN | NLC_TRUNCATE))) {
+       if (nflags & NLC_TRUNCATE)
+           return (EPERM);
+       if ((nflags & (NLC_OPEN | NLC_WRITE)) == (NLC_OPEN | NLC_WRITE)) {
+           if ((nflags & NLC_APPEND) == 0)
                return (EPERM);
        }
     }
@@ -853,12 +1001,19 @@ naccess_va(struct vattr *va, int vmode, struct ucred *cred)
     /*
      * Check owner perms.
      *
-     * If VOWN is set the owner of the file is allowed no matter when
+     * If NLC_OWN is set the owner of the file is allowed no matter when
      * the owner-mode bits say (utimes).
      */
+    vmode = 0;
+    if (nflags & NLC_READ)
+       vmode |= S_IRUSR;
+    if (nflags & NLC_WRITE)
+       vmode |= S_IWUSR;
+    if (nflags & NLC_EXEC)
+       vmode |= S_IXUSR;
+
     if (cred->cr_uid == va->va_uid) {
-       if ((vmode & VOWN) == 0) {
-           vmode &= S_IRWXU;
+       if ((nflags & NLC_OWN) == 0) {
            if ((vmode & va->va_mode) != vmode)
                return(EACCES);
        }
@@ -866,23 +1021,21 @@ naccess_va(struct vattr *va, int vmode, struct ucred *cred)
     }
 
     /*
-     * If VSVTX is set only the owner may create or delete the file.
-     * This bit is typically set for VDELETE checks from unlink or
-     * the source file in a rename, and for VCREATE checks from the
-     * target file in a rename.
+     * If NLC_STICKY is set only the owner may delete or rename a file.
+     * This bit is typically set on /tmp.
      *
-     * Note that other V bits are not typically set in the VSVTX case.
-     * For creations and deletions we usually just care about directory
-     * permissions, not file permissions.  So if this test passes the
-     * return value winds up being 0.
+     * Note that the NLC_READ/WRITE/EXEC bits are not typically set in
+     * the specific delete or rename case.  For deletions and renames we
+     * usually just care about directory permissions, not file permissions.
      */
-    if (vmode & VSVTX)
+    if ((nflags & NLC_STICKY) &&
+       (nflags & (NLC_RENAME_SRC | NLC_RENAME_DST | NLC_DELETE))) {
        return(EACCES);
+    }
 
     /*
      * Check group perms
      */
-    vmode &= S_IRWXU;
     vmode >>= 3;
     for (i = 0; i < cred->cr_ngroups; ++i) {
        if (va->va_gid == cred->cr_groups[i]) {
index 09c36aa..a889135 100644 (file)
@@ -92,7 +92,8 @@ static int getutimes (const struct timeval *, struct timespec *);
 static int setfown (struct vnode *, uid_t, gid_t);
 static int setfmode (struct vnode *, int);
 static int setfflags (struct vnode *, int);
-static int setutimes (struct vnode *, const struct timespec *, int);
+static int setutimes (struct vnode *, struct vattr *,
+                       const struct timespec *, int);
 static int     usermount = 0;  /* if 1, non-root can mount fs. */
 
 int (*union_dircheckp) (struct thread *, struct vnode **, struct file *);
@@ -1656,6 +1657,7 @@ sys_chroot(struct chroot_args *uap)
                nlookup_done(&nd);
                return(error);
        }
+       nd.nl_flags |= NLC_EXEC;
        error = nlookup(&nd);
        if (error == 0)
                error = kern_chroot(&nd.nl_nch);
@@ -1701,7 +1703,7 @@ kern_open(struct nlookupdata *nd, int oflags, int mode, int *res)
        if (error)
                return (error);
        fp = nfp;
-       cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &S_ISTXT;
+       cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
 
        /*
         * XXX p_dupfd is a real mess.  It allows a device to return a
@@ -2037,9 +2039,13 @@ kern_link(struct nlookupdata *nd, struct nlookupdata *linknd)
        /*
         * Lookup the source and obtained a locked vnode.
         *
+        * You may only hardlink a file which you have write permission
+        * on or which you own.
+        *
         * XXX relookup on vget failure / race ?
         */
        bwillinode(1);
+       nd->nl_flags |= NLC_WRITE | NLC_OWN | NLC_HLINK;
        if ((error = nlookup(nd)) != 0)
                return (error);
        vp = nd->nl_nch.ncp->nc_vp;
@@ -2564,7 +2570,6 @@ sys_chflags(struct chflags_args *uap)
 
        vp = NULL;
        error = nlookup_init(&nd, uap->path, UIO_USERSPACE, NLC_FOLLOW);
-       /* XXX Add NLC flag indicating modifying operation? */
        if (error == 0)
                error = nlookup(&nd);
        if (error == 0)
@@ -2594,7 +2599,6 @@ sys_lchflags(struct lchflags_args *uap)
 
        vp = NULL;
        error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0);
-       /* XXX Add NLC flag indicating modifying operation? */
        if (error == 0)
                error = nlookup(&nd);
        if (error == 0)
@@ -2660,7 +2664,6 @@ kern_chmod(struct nlookupdata *nd, int mode)
        struct vnode *vp;
        int error;
 
-       /* XXX Add NLC flag indicating modifying operation? */
        if ((error = nlookup(nd)) != 0)
                return (error);
        if ((error = cache_vref(&nd->nl_nch, nd->nl_cred, &vp)) != 0)
@@ -2761,7 +2764,6 @@ kern_chown(struct nlookupdata *nd, int uid, int gid)
        struct vnode *vp;
        int error;
 
-       /* XXX Add NLC flag indicating modifying operation? */
        if ((error = nlookup(nd)) != 0)
                return (error);
        if ((error = cache_vref(&nd->nl_nch, nd->nl_cred, &vp)) != 0)
@@ -2849,26 +2851,20 @@ getutimes(const struct timeval *tvp, struct timespec *tsp)
 }
 
 static int
-setutimes(struct vnode *vp, const struct timespec *ts, int nullflag)
+setutimes(struct vnode *vp, struct vattr *vattr,
+         const struct timespec *ts, int nullflag)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
        int error;
-       struct vattr vattr;
 
-       /*
-        * note: vget is required for any operation that might mod the vnode
-        * so VINACTIVE is properly cleared.
-        */
-       if ((error = vget(vp, LK_EXCLUSIVE)) == 0) {
-               VATTR_NULL(&vattr);
-               vattr.va_atime = ts[0];
-               vattr.va_mtime = ts[1];
-               if (nullflag)
-                       vattr.va_vaflags |= VA_UTIMES_NULL;
-               error = VOP_SETATTR(vp, &vattr, p->p_ucred);
-               vput(vp);
-       }
+       VATTR_NULL(vattr);
+       vattr->va_atime = ts[0];
+       vattr->va_mtime = ts[1];
+       if (nullflag)
+               vattr->va_vaflags |= VA_UTIMES_NULL;
+       error = VOP_SETATTR(vp, vattr, p->p_ucred);
+
        return error;
 }
 
@@ -2877,11 +2873,18 @@ kern_utimes(struct nlookupdata *nd, struct timeval *tptr)
 {
        struct timespec ts[2];
        struct vnode *vp;
+       struct vattr vattr;
        int error;
 
        if ((error = getutimes(tptr, ts)) != 0)
                return (error);
-       /* XXX Add NLC flag indicating modifying operation? */
+
+       /*
+        * NOTE: utimes() succeeds for the owner even if the file
+        * is not user-writable.
+        */
+       nd->nl_flags |= NLC_OWN | NLC_WRITE;
+
        if ((error = nlookup(nd)) != 0)
                return (error);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
@@ -2890,12 +2893,15 @@ kern_utimes(struct nlookupdata *nd, struct timeval *tptr)
                return (error);
 
        /*
-        * NOTE: utimes() succeeds for the owner even if the file
-        * is not user-writable.
+        * note: vget is required for any operation that might mod the vnode
+        * so VINACTIVE is properly cleared.
         */
-       if ((error = vn_writechk(vp, &nd->nl_nch)) == 0 &&
-           (error = VOP_ACCESS(vp, VWRITE | VOWN, nd->nl_cred)) == 0) {
-               error = setutimes(vp, ts, tptr == NULL);
+       if ((error = vn_writechk(vp, &nd->nl_nch)) == 0) {
+               error = vget(vp, LK_EXCLUSIVE);
+               if (error == 0) {
+                       error = setutimes(vp, &vattr, ts, (tptr == NULL));
+                       vput(vp);
+               }
        }
        vrele(vp);
        return (error);
@@ -2949,6 +2955,11 @@ sys_lutimes(struct lutimes_args *uap)
        return (error);
 }
 
+/*
+ * Set utimes on a file descriptor.  The creds used to open the
+ * file are used to determine whether the operation is allowed
+ * or not.
+ */
 int
 kern_futimes(int fd, struct timeval *tptr)
 {
@@ -2956,6 +2967,8 @@ kern_futimes(int fd, struct timeval *tptr)
        struct proc *p = td->td_proc;
        struct timespec ts[2];
        struct file *fp;
+       struct vnode *vp;
+       struct vattr vattr;
        int error;
 
        error = getutimes(tptr, ts);
@@ -2965,8 +2978,22 @@ kern_futimes(int fd, struct timeval *tptr)
                return (error);
        if (fp->f_nchandle.ncp)
                error = ncp_writechk(&fp->f_nchandle);
-       if (error == 0)
-               error =  setutimes((struct vnode *)fp->f_data, ts, tptr == NULL);
+       if (error == 0) {
+               vp = fp->f_data;
+               error = vget(vp, LK_EXCLUSIVE);
+               if (error == 0) {
+                       error = VOP_GETATTR(vp, &vattr);
+                       if (error == 0) {
+                               error = naccess_va(&vattr, NLC_OWN | NLC_WRITE,
+                                                  fp->f_cred);
+                       }
+                       if (error == 0) {
+                               error = setutimes(vp, &vattr, ts,
+                                                 (tptr == NULL));
+                       }
+                       vput(vp);
+               }
+       }
        fdrop(fp);
        return (error);
 }
@@ -3002,7 +3029,7 @@ kern_truncate(struct nlookupdata *nd, off_t length)
 
        if (length < 0)
                return(EINVAL);
-       /* XXX Add NLC flag indicating modifying operation? */
+       nd->nl_flags |= NLC_WRITE | NLC_TRUNCATE;
        if ((error = nlookup(nd)) != 0)
                return (error);
        if ((error = ncp_writechk(&nd->nl_nch)) != 0)
@@ -3015,8 +3042,7 @@ kern_truncate(struct nlookupdata *nd, off_t length)
        }
        if (vp->v_type == VDIR) {
                error = EISDIR;
-       } else if ((error = vn_writechk(vp, &nd->nl_nch)) == 0 &&
-           (error = VOP_ACCESS(vp, VWRITE, nd->nl_cred)) == 0) {
+       } else if ((error = vn_writechk(vp, &nd->nl_nch)) == 0) {
                VATTR_NULL(&vattr);
                vattr.va_size = length;
                error = VOP_SETATTR(vp, &vattr, nd->nl_cred);
@@ -3066,6 +3092,10 @@ kern_ftruncate(int fd, off_t length)
                error = EINVAL;
                goto done;
        }
+       if (fp->f_flag & FAPPENDONLY) { /* inode was set s/uapnd */
+               error = EINVAL;
+               goto done;
+       }
        vp = (struct vnode *)fp->f_data;
        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
        if (vp->v_type == VDIR) {
@@ -3137,7 +3167,7 @@ kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond)
        int error;
 
        bwillinode(1);
-       fromnd->nl_flags |= NLC_REFDVP | NLC_DELETE;
+       fromnd->nl_flags |= NLC_REFDVP | NLC_RENAME_SRC;
        if ((error = nlookup(fromnd)) != 0)
                return (error);
        if ((fnchd.ncp = fromnd->nl_nch.ncp->nc_parent) == NULL)
@@ -3158,7 +3188,7 @@ kern_rename(struct nlookupdata *fromnd, struct nlookupdata *tond)
        fromnd->nl_flags &= ~NLC_NCPISLOCKED;
        cache_unlock(&fromnd->nl_nch);
 
-       tond->nl_flags |= NLC_RENAME | NLC_REFDVP;
+       tond->nl_flags |= NLC_RENAME_DST | NLC_REFDVP;
        if ((error = nlookup(tond)) != 0) {
                cache_drop(&fnchd);
                return (error);
index d0ab7c8..4bdf933 100644 (file)
@@ -131,7 +131,7 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
        struct ucred *cred = nd->nl_cred;
        struct vattr vat;
        struct vattr *vap = &vat;
-       int mode, error;
+       int error;
 
        /*
         * Lookup the path and create or obtain the vnode.  After a
@@ -142,6 +142,16 @@ vn_open(struct nlookupdata *nd, struct file *fp, int fmode, int cmode)
         * XXX with only a little work we should be able to avoid locking
         * the vnode if FWRITE, O_CREAT, and O_TRUNC are *not* set.
         */
+       nd->nl_flags |= NLC_OPEN;
+       if (fmode & O_APPEND)
+               nd->nl_flags |= NLC_APPEND;
+       if (fmode & O_TRUNC)
+               nd->nl_flags |= NLC_TRUNCATE;
+       if (fmode & FREAD)
+               nd->nl_flags |= NLC_READ;
+       if (fmode & FWRITE)
+               nd->nl_flags |= NLC_WRITE;
+
        if (fmode & O_CREAT) {
                /*
                 * CONDITIONAL CREATE FILE CASE
@@ -219,7 +229,6 @@ again:
                goto bad;
        }
        if ((fmode & O_CREAT) == 0) {
-               mode = 0;
                if (fmode & (FWRITE | O_TRUNC)) {
                        if (vp->v_type == VDIR) {
                                error = EISDIR;
@@ -241,27 +250,6 @@ again:
                                }
                                goto bad;
                        }
-                       mode |= VWRITE;
-               }
-               if (fmode & FREAD)
-                       mode |= VREAD;
-               if (mode) {
-                       error = VOP_ACCESS(vp, mode, cred);
-                       if (error) {
-                               /*
-                                * Special stale handling, re-resolve the
-                                * vnode.
-                                */
-                               if (error == ESTALE) {
-                                       vput(vp);
-                                       vp = NULL;
-                                       cache_setunresolved(&nd->nl_nch);
-                                       error = cache_resolve(&nd->nl_nch, cred);
-                                       if (error == 0)
-                                               goto again;
-                               }
-                               goto bad;
-                       }
                }
        }
        if (fmode & O_TRUNC) {
@@ -284,6 +272,8 @@ again:
         * used to open the file.
         */
        if (fp) {
+               if (nd->nl_flags & NLC_APPENDONLY)
+                       fmode |= FAPPENDONLY;
                fp->f_nchandle = nd->nl_nch;
                cache_zero(&nd->nl_nch);
                cache_unlock(&fp->f_nchandle);
index 7df1b0e..df00fe2 100644 (file)
 
 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
 #define FREVOKED       0x10000000      /* revoked by fdrevoke() */
+#define FAPPENDONLY    0x20000000      /* O_APPEND cannot be changed */
 #endif
 
 #define O_FMASK                (O_FBLOCKING|O_FNONBLOCKING|O_FAPPEND|O_FOFFSET|\
 
 /* bits to save after open */
 #define        FMASK           (FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK|\
-                        O_DIRECT|O_MAPONREAD)
+                        FAPPENDONLY|FREVOKED|O_DIRECT|O_MAPONREAD)
 /* bits settable by fcntl(F_SETFL, ...) */
 #define        FCNTLFLAGS      (FAPPEND|FASYNC|FFSYNC|FNONBLOCK|FPOSIXSHM|\
                         O_DIRECT|O_MAPONREAD)
index 3859bc9..cec3b96 100644 (file)
@@ -94,6 +94,11 @@ struct nlookupdata {
        int             nl_vp_fmode;
 };
 
+/*
+ * NOTE: nlookup() flags related to open checks do not actually perform
+ *      any modifying operation.  e.g. the file isn't created, truncated,
+ *      etc.  vn_open() handles that.
+ */
 #define NLC_FOLLOW             0x00000001      /* follow leaf symlink */
 #define NLC_NOCROSSMOUNT       0x00000002      /* do not cross mount points */
 #define NLC_HASBUF             0x00000004      /* nl_path is allocated */
@@ -101,13 +106,41 @@ struct nlookupdata {
 #define NLC_WILLBEDIR          0x00000010
 #define NLC_NCPISLOCKED                0x00000020
 #define NLC_LOCKVP             0x00000040      /* nl_open_vp from vn_open */
-#define NLC_CREATE             0x00000080
-#define NLC_DELETE             0x00000100
-#define NLC_RENAME             0x00000200      /* rename (target) */
+#define NLC_CREATE             0x00000080      /* do create checks */
+#define NLC_DELETE             0x00000100      /* do delete checks */
+#define NLC_RENAME_DST         0x00000200      /* do rename checks (target) */
+#define NLC_OPEN               0x00000400      /* do open checks */
+#define NLC_TRUNCATE           0x00000800      /* do truncation checks */
+#define NLC_HLINK              0x00001000      /* do hardlink checks */
+#define NLC_RENAME_SRC         0x00002000      /* do rename checks (source) */
+#define NLC_UNUSED00004000     0x00004000
+#define NLC_UNUSED00008000     0x00008000
 #define NLC_NFS_RDONLY         0x00010000      /* set by nfs_namei() only */
 #define NLC_NFS_NOSOFTLINKTRAV 0x00020000      /* do not traverse softlnks */
 #define NLC_REFDVP             0x00040000      /* set ref'd/unlocked nl_dvp */
 
+#define NLC_APPEND             0x00100000      /* open check: append */
+#define NLC_UNUSED00200000     0x00200000
+
+#define NLC_READ               0x00400000      /* require read access */
+#define NLC_WRITE              0x00800000      /* require write access */
+#define NLC_EXEC               0x01000000      /* require execute access */
+#define NLC_EXCL               0x02000000      /* open check: exclusive */
+#define NLC_OWN                        0x04000000      /* open check: owner override */
+#define NLC_UNUSED08000000     0x08000000
+#define NLC_STICKY             0x10000000      /* indicate sticky case */
+#define NLC_APPENDONLY         0x20000000      /* indicate append-only */
+#define NLC_IMMUTABLE          0x40000000      /* indicate immutable set */
+#define NLC_WRITABLE           0x80000000      /* indicate writeable */
+
+/*
+ * All checks.  If any of these bits are set general user/group/world
+ * permission checks will be done by nlookup().
+ */
+#define NLC_ALLCHKS            (NLC_CREATE | NLC_DELETE | NLC_RENAME_DST | \
+                                NLC_OPEN | NLC_TRUNCATE | NLC_RENAME_SRC | \
+                                NLC_READ | NLC_WRITE | NLC_EXEC | NLC_OWN)
+
 #ifdef _KERNEL
 
 int nlookup_init(struct nlookupdata *, const char *, enum uio_seg, int);
@@ -122,6 +155,7 @@ int nlookup(struct nlookupdata *);
 int nreadsymlink(struct nlookupdata *nd, struct nchandle *nch, 
                                struct nlcomponent *nlc);
 int naccess(struct nchandle *nch, int vmode, struct ucred *cred, int *stickyp);
+int naccess_va(struct vattr *va, int nflags, struct ucred *cred);
 
 #endif
 
index 0031e6c..ce3f111 100644 (file)
@@ -314,16 +314,7 @@ struct vnode {
 /*
  * Modes.  Note that these V-modes must match file S_I*USR, SUID, SGID,
  * and SVTX flag bits.
- *
- * VOWN, VCREATE, VDELETE, VRENAME, and VEXCL may only be used in
- * naccess() calls.
  */
-#define VRENAME        0200000         /* set with VCREATE or VDELETE if rename */
-#define VOWN   0100000         /* succeed if file owner or (other flags) */
-#define VDELETE        040000          /* delete if the file/dir exists */
-#define VCREATE        020000          /* create if the file/dir does not exist */
-#define VEXCL  010000          /* error if the file/dir already exists */
-
 #define        VSUID   04000           /* set user id on execution */
 #define        VSGID   02000           /* set group id on execution */
 #define        VSVTX   01000           /* save swapped text even after use */
index 7bf177e..5198a72 100644 (file)
@@ -1380,8 +1380,6 @@ ext2_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ip->i_uid) {
-               if (mode & VOWN)
-                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 181c9e5..08469b6 100644 (file)
@@ -750,8 +750,6 @@ hpfs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == hp->h_uid) {
-               if (mode & VOWN)
-                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 045d742..0a2052b 100644 (file)
@@ -280,8 +280,6 @@ msdosfs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == pmp->pm_uid) {
-               if (mode & VOWN)
-                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 4b2f1df..0612129 100644 (file)
@@ -452,7 +452,7 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 
        pubflag = nfs_ispublicfh(fhp);
 
-       error = nfs_namei(&nd, cred, NAMEI_LOOKUP, NULL, &vp,
+       error = nfs_namei(&nd, cred, 0, NULL, &vp,
                fhp, len, slp, nam, &md, &dpos,
                &dirp, td, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
 
@@ -1579,7 +1579,7 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
         * be valid at all if an error occurs so we have to invalidate it
         * prior to calling nfsm_reply ( which might goto nfsmout ).
         */
-       error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
                          fhp, len, slp, nam, &md, &dpos, &dirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        mp = vfs_getvfs(&fhp->fh_fsid);
@@ -1851,7 +1851,7 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
         * nfsmout.
         */
 
-       error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
                          fhp, len, slp, nam, &md, &dpos, &dirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (dirp)
@@ -1988,7 +1988,7 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
        nfsm_srvmtofh(fhp);
        nfsm_srvnamesiz(len);
 
-       error = nfs_namei(&nd, cred, NAMEI_DELETE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp,
                          fhp, len, slp, nam, &md, &dpos, &dirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (dirp) {
@@ -2093,7 +2093,8 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
         * the second nfs_namei() call, in case it is remapped.
         */
        saved_uid = cred->cr_uid;
-       error = nfs_namei(&fromnd, cred, NAMEI_DELETE, NULL, NULL,
+       error = nfs_namei(&fromnd, cred, NLC_RENAME_SRC,
+                         NULL, NULL,
                          ffhp, len, slp, nam, &md, &dpos, &fdirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (fdirp) {
@@ -2119,7 +2120,7 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
        nfsm_strsiz(len2, NFS_MAXNAMLEN);
        cred->cr_uid = saved_uid;
 
-       error = nfs_namei(&tond, cred, NAMEI_RENAME, NULL, NULL,
+       error = nfs_namei(&tond, cred, NLC_RENAME_DST, NULL, NULL,
                          tfhp, len2, slp, nam, &md, &dpos, &tdirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (tdirp) {
@@ -2324,7 +2325,7 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
                goto out1;
        }
 
-       error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
                          dfhp, len, slp, nam, &md, &dpos, &dirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (dirp) {
@@ -2418,7 +2419,7 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
        nfsm_srvmtofh(fhp);
        nfsm_srvnamesiz(len);
 
-       error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
                        fhp, len, slp, nam, &md, &dpos, &dirp,
                        td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (dirp) {
@@ -2548,7 +2549,7 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
        nfsm_srvmtofh(fhp);
        nfsm_srvnamesiz(len);
 
-       error = nfs_namei(&nd, cred, NAMEI_CREATE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
                          fhp, len, slp, nam, &md, &dpos, &dirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (dirp) {
@@ -2667,7 +2668,7 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
        nfsm_srvmtofh(fhp);
        nfsm_srvnamesiz(len);
 
-       error = nfs_namei(&nd, cred, NAMEI_DELETE, &dvp, &vp,
+       error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp,
                          fhp, len, slp, nam, &md, &dpos, &dirp,
                          td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
        if (dirp) {
index a90a7cc..64274f8 100644 (file)
@@ -1443,7 +1443,7 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
  * to cleanup.
  */
 int
-nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nameiop,
+nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nflags,
        struct vnode **dvpp, struct vnode **vpp,
        fhandle_t *fhp, int len,
        struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
@@ -1451,7 +1451,6 @@ nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nameiop,
        int kerbflag, int pubflag)
 {
        int i, rem;
-       int flags;
        struct mbuf *md;
        char *fromcp, *tocp, *cp;
        char *namebuf;
@@ -1461,7 +1460,6 @@ nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nameiop,
        int error, rdonly;
 
        namebuf = objcache_get(namei_oc, M_WAITOK);
-       flags = 0;
        *dirpp = NULL;
 
        /*
@@ -1575,15 +1573,11 @@ nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nameiop,
         * that dp is ref'd, but we no longer 'own' the ref (*dirpp owns it).
         */
        if (pubflag == 0) {
-               flags |= NLC_NFS_NOSOFTLINKTRAV;
-               flags |= NLC_NOCROSSMOUNT;
+               nflags |= NLC_NFS_NOSOFTLINKTRAV;
+               nflags |= NLC_NOCROSSMOUNT;
        }
        if (rdonly)
-               flags |= NLC_NFS_RDONLY;
-       if (nameiop == NAMEI_CREATE)
-               flags |= NLC_CREATE;
-       if (nameiop == NAMEI_RENAME)
-               flags |= NLC_RENAME;
+               nflags |= NLC_NFS_RDONLY;
 
        /*
         * We need a starting ncp from the directory vnode dp.  dp must not
@@ -1595,7 +1589,7 @@ nfs_namei(struct nlookupdata *nd, struct ucred *cred, int nameiop,
         */
        if ((error = cache_fromdvp(dp, cred, 1, &nch)) != 0)
                goto out;
-       nlookup_init_raw(nd, namebuf, UIO_SYSSPACE, flags, cred, &nch);
+       nlookup_init_raw(nd, namebuf, UIO_SYSSPACE, nflags, cred, &nch);
        cache_drop(&nch);
 
        /*
index c1246fe..af1a2d1 100644 (file)
@@ -460,8 +460,6 @@ ntfs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ip->i_mp->ntm_uid) {
-               if (mode & VOWN)
-                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
index 1faaaae..0a1ce19 100644 (file)
@@ -145,8 +145,6 @@ nwfs_access(struct vop_access_args *ap)
                mode >>= 3;
                if (!groupmember(nmp->m.gid, cred))
                        mode >>= 3;
-       } else if (mode & VOWN) {
-               return (0);
        }
        error = (((vp->v_type == VREG) ? nmp->m.file_mode : nmp->m.dir_mode) & mode) == mode ? 0 : EACCES;
        return error;
index eab915b..e3a5068 100644 (file)
@@ -148,8 +148,6 @@ smbfs_access(struct vop_access_args *ap)
                mode >>= 3;
                if (!groupmember(smp->sm_args.gid, cred))
                        mode >>= 3;
-       } else if (mode & VOWN) {
-               return (0);
        }
        error = (((vp->v_type == VREG) ? smp->sm_args.file_mode : smp->sm_args.dir_mode) & mode) == mode ? 0 : EACCES;
        return error;
index d358741..dc9e49c 100644 (file)
@@ -240,8 +240,6 @@ udf_access(struct vop_access_args *a)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == node->fentry->uid) {
-               if (a_mode & VOWN)
-                       return (0);
                if (a_mode & VEXEC)
                        mask |= S_IXUSR;
                if (a_mode & VREAD)
index bb0ef4f..14ca305 100644 (file)
@@ -94,7 +94,6 @@ static int ufs_missingop (struct vop_generic_args *ap);
 static int ufs_mkdir (struct vop_old_mkdir_args *);
 static int ufs_mknod (struct vop_old_mknod_args *);
 static int ufs_mmap (struct vop_mmap_args *);
-static int ufs_open (struct vop_open_args *);
 static int ufs_print (struct vop_print_args *);
 static int ufs_readdir (struct vop_readdir_args *);
 static int ufs_readlink (struct vop_readlink_args *);
@@ -266,32 +265,6 @@ ufs_mknod(struct vop_old_mknod_args *ap)
 }
 
 /*
- * Open called.
- *
- * Nothing to do.
- *
- * ufs_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
- *         struct file *a_fp)
- */
-/* ARGSUSED */
-static
-int
-ufs_open(struct vop_open_args *ap)
-{
-       struct vnode *vp = ap->a_vp;
-
-       /*
-        * Files marked append-only must be opened for appending.
-        */
-       if ((VTOI(vp)->i_flags & APPEND) &&
-           (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) {
-               return (EPERM);
-       }
-
-       return (vop_stdopen(ap));
-}
-
-/*
  * Close called.
  *
  * Update the times on the inode.
@@ -349,9 +322,11 @@ ufs_access(struct vop_access_args *ap)
                }
        }
 
+#if 0  /* handled by kernel now */
        /* If immutable bit set, nobody gets to write it. */
        if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
                return (EPERM);
+#endif
 
        /* Otherwise, user id 0 always gets access. */
        if (cred->cr_uid == 0)
@@ -361,8 +336,6 @@ ufs_access(struct vop_access_args *ap)
 
        /* Otherwise, check the owner. */
        if (cred->cr_uid == ip->i_uid) {
-               if (mode & VOWN)
-                       return (0);
                if (mode & VEXEC)
                        mask |= S_IXUSR;
                if (mode & VREAD)
@@ -741,15 +714,19 @@ ufs_remove(struct vop_old_remove_args *ap)
        int error;
 
        ip = VTOI(vp);
+#if 0  /* handled by kernel now */
        if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
            (VTOI(dvp)->i_flags & APPEND)) {
                error = EPERM;
                goto out;
        }
+#endif
        error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
        VN_KNOTE(vp, NOTE_DELETE);
        VN_KNOTE(dvp, NOTE_WRITE);
+#if 0
 out:
+#endif
        return (error);
 }
 
@@ -782,10 +759,12 @@ ufs_link(struct vop_old_link_args *ap)
                error = EMLINK;
                goto out1;
        }
+#if 0  /* handled by kernel now, also DragonFly allows this */
        if (ip->i_flags & (IMMUTABLE | APPEND)) {
                error = EPERM;
                goto out1;
        }
+#endif
        ip->i_effnlink++;
        ip->i_nlink++;
        ip->i_flag |= IN_CHANGE;
@@ -926,11 +905,13 @@ abortit:
                return (error);
        }
 
+#if 0  /* handled by kernel now */
        if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
            (VTOI(tdvp)->i_flags & APPEND))) {
                error = EPERM;
                goto abortit;
        }
+#endif
 
        /*
         * Renaming a file to itself has no effect.  The upper layers should
@@ -956,12 +937,14 @@ abortit:
                error = EMLINK;
                goto abortit;
        }
+#if 0  /* handled by kernel now */
        if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
            || (dp->i_flags & APPEND)) {
                vn_unlock(fvp);
                error = EPERM;
                goto abortit;
        }
+#endif
        if ((ip->i_mode & IFMT) == IFDIR) {
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
@@ -1563,11 +1546,13 @@ ufs_rmdir(struct vop_old_rmdir_args *ap)
                error = ENOTEMPTY;
                goto out;
        }
+#if 0  /* handled by kernel now */
        if ((dp->i_flags & APPEND)
            || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
                error = EPERM;
                goto out;
        }
+#endif
        /*
         * Delete reference to directory before purging
         * inode.  If we crash in between, the directory
@@ -2375,7 +2360,7 @@ static struct vop_ops ufs_vnode_vops = {
        .vop_old_mkdir =        ufs_mkdir,
        .vop_old_mknod =        ufs_mknod,
        .vop_mmap =             ufs_mmap,
-       .vop_open =             ufs_open,
+       .vop_open =             vop_stdopen,
        .vop_pathconf =         vop_stdpathconf,
        .vop_poll =             vop_stdpoll,
        .vop_kqfilter =         ufs_kqfilter,