don't clear set-gid when su creates file when not groupmember
[unix-history] / usr / src / sys / ufs / lfs / lfs_vnops.c
index cf71517..6073578 100644 (file)
@@ -1,4 +1,10 @@
-/*     lfs_vnops.c     6.14    84/08/29        */
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ *     @(#)lfs_vnops.c 7.3 (Berkeley) %G%
+ */
 
 #include "param.h"
 #include "systm.h"
 
 #include "param.h"
 #include "systm.h"
@@ -113,31 +119,31 @@ copen(mode, arg, fname)
        register struct inode *ip;
        register struct file *fp;
        register struct nameidata *ndp = &u.u_nd;
        register struct inode *ip;
        register struct file *fp;
        register struct nameidata *ndp = &u.u_nd;
-       int i;
+       int indx;
 
 
-#ifdef notdef
-       if ((mode&(FREAD|FWRITE)) == 0) {
-               u.u_error = EINVAL;
+       fp = falloc();
+       if (fp == NULL)
                return;
                return;
-       }
-#endif
+       indx = u.u_r.r_val1;
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
        if (mode&FCREAT) {
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = fname;
        if (mode&FCREAT) {
-               ndp->ni_nameiop = CREATE | FOLLOW;
+               if (mode & FEXCL)
+                       ndp->ni_nameiop = CREATE;
+               else
+                       ndp->ni_nameiop = CREATE | FOLLOW;
                ip = namei(ndp);
                if (ip == NULL) {
                        if (u.u_error)
                ip = namei(ndp);
                if (ip == NULL) {
                        if (u.u_error)
-                               return;
+                               goto bad1;
                        ip = maknode(arg&07777&(~ISVTX), ndp);
                        if (ip == NULL)
                        ip = maknode(arg&07777&(~ISVTX), ndp);
                        if (ip == NULL)
-                               return;
+                               goto bad1;
                        mode &= ~FTRUNC;
                } else {
                        if (mode&FEXCL) {
                                u.u_error = EEXIST;
                        mode &= ~FTRUNC;
                } else {
                        if (mode&FEXCL) {
                                u.u_error = EEXIST;
-                               iput(ip);
-                               return;
+                               goto bad;
                        }
                        mode &= ~FCREAT;
                }
                        }
                        mode &= ~FCREAT;
                }
@@ -145,7 +151,7 @@ copen(mode, arg, fname)
                ndp->ni_nameiop = LOOKUP | FOLLOW;
                ip = namei(ndp);
                if (ip == NULL)
                ndp->ni_nameiop = LOOKUP | FOLLOW;
                ip = namei(ndp);
                if (ip == NULL)
-                       return;
+                       goto bad1;
        }
        if ((ip->i_mode & IFMT) == IFSOCK) {
                u.u_error = EOPNOTSUPP;
        }
        if ((ip->i_mode & IFMT) == IFSOCK) {
                u.u_error = EOPNOTSUPP;
@@ -164,9 +170,6 @@ copen(mode, arg, fname)
                        }
                }
        }
                        }
                }
        }
-       fp = falloc();
-       if (fp == NULL)
-               goto bad;
        if (mode&FTRUNC)
                itrunc(ip, (u_long)0);
        IUNLOCK(ip);
        if (mode&FTRUNC)
                itrunc(ip, (u_long)0);
        IUNLOCK(ip);
@@ -174,23 +177,22 @@ copen(mode, arg, fname)
        fp->f_type = DTYPE_INODE;
        fp->f_ops = &inodeops;
        fp->f_data = (caddr_t)ip;
        fp->f_type = DTYPE_INODE;
        fp->f_ops = &inodeops;
        fp->f_data = (caddr_t)ip;
-       i = u.u_r.r_val1;
        if (setjmp(&u.u_qsave)) {
                if (u.u_error == 0)
                        u.u_error = EINTR;
        if (setjmp(&u.u_qsave)) {
                if (u.u_error == 0)
                        u.u_error = EINTR;
-               u.u_ofile[i] = NULL;
+               u.u_ofile[indx] = NULL;
                closef(fp);
                return;
        }
        u.u_error = openi(ip, mode);
        if (u.u_error == 0)
                return;
                closef(fp);
                return;
        }
        u.u_error = openi(ip, mode);
        if (u.u_error == 0)
                return;
-       u.u_ofile[i] = NULL;
-       fp->f_count--;
-       irele(ip);
-       return;
+       ILOCK(ip);
 bad:
        iput(ip);
 bad:
        iput(ip);
+bad1:
+       u.u_ofile[indx] = NULL;
+       fp->f_count--;
 }
 
 /*
 }
 
 /*
@@ -329,7 +331,8 @@ symlink()
        ip = maknode(IFLNK | 0777, ndp);
        if (ip == NULL)
                return;
        ip = maknode(IFLNK | 0777, ndp);
        if (ip == NULL)
                return;
-       u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
+       u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, (off_t)0, 0,
+           (int *)0);
        /* handle u.u_error != 0 */
        iput(ip);
 }
        /* handle u.u_error != 0 */
        iput(ip);
 }
@@ -511,10 +514,11 @@ readlink()
        if (ip == NULL)
                return;
        if ((ip->i_mode&IFMT) != IFLNK) {
        if (ip == NULL)
                return;
        if ((ip->i_mode&IFMT) != IFLNK) {
-               u.u_error = ENXIO;
+               u.u_error = EINVAL;
                goto out;
        }
                goto out;
        }
-       u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
+       u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, (off_t)0, 0,
+           &resid);
 out:
        iput(ip);
        u.u_r.r_val1 = uap->count - resid;
 out:
        iput(ip);
        u.u_r.r_val1 = uap->count - resid;
@@ -533,7 +537,7 @@ chmod()
 
        if ((ip = owner(uap->fname, FOLLOW)) == NULL)
                return;
 
        if ((ip = owner(uap->fname, FOLLOW)) == NULL)
                return;
-       chmod1(ip, uap->fmode);
+       u.u_error = chmod1(ip, uap->fmode);
        iput(ip);
 }
 
        iput(ip);
 }
 
@@ -556,7 +560,7 @@ fchmod()
        if (u.u_uid != ip->i_uid && !suser())
                return;
        ILOCK(ip);
        if (u.u_uid != ip->i_uid && !suser())
                return;
        ILOCK(ip);
-       chmod1(ip, uap->fmode);
+       u.u_error = chmod1(ip, uap->fmode);
        IUNLOCK(ip);
 }
 
        IUNLOCK(ip);
 }
 
@@ -569,9 +573,12 @@ chmod1(ip, mode)
        register int mode;
 {
 
        register int mode;
 {
 
+       if (ip->i_fs->fs_ronly)
+               return (EROFS);
        ip->i_mode &= ~07777;
        if (u.u_uid) {
        ip->i_mode &= ~07777;
        if (u.u_uid) {
-               mode &= ~ISVTX;
+               if ((ip->i_mode & IFMT) != IFDIR)
+                       mode &= ~ISVTX;
                if (!groupmember(ip->i_gid))
                        mode &= ~ISGID;
        }
                if (!groupmember(ip->i_gid))
                        mode &= ~ISGID;
        }
@@ -579,6 +586,7 @@ chmod1(ip, mode)
        ip->i_flag |= ICHG;
        if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
                xrele(ip);
        ip->i_flag |= ICHG;
        if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
                xrele(ip);
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -593,7 +601,7 @@ chown()
                int     gid;
        } *uap = (struct a *)u.u_ap;
 
                int     gid;
        } *uap = (struct a *)u.u_ap;
 
-       if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL)
+       if ((ip = owner(uap->fname, NOFOLLOW)) == NULL)
                return;
        u.u_error = chown1(ip, uap->uid, uap->gid);
        iput(ip);
                return;
        u.u_error = chown1(ip, uap->uid, uap->gid);
        iput(ip);
@@ -616,8 +624,6 @@ fchown()
        if (fp == NULL)
                return;
        ip = (struct inode *)fp->f_data;
        if (fp == NULL)
                return;
        ip = (struct inode *)fp->f_data;
-       if (!suser())
-               return;
        ILOCK(ip);
        u.u_error = chown1(ip, uap->uid, uap->gid);
        IUNLOCK(ip);
        ILOCK(ip);
        u.u_error = chown1(ip, uap->uid, uap->gid);
        IUNLOCK(ip);
@@ -635,10 +641,16 @@ chown1(ip, uid, gid)
        register long change;
 #endif
 
        register long change;
 #endif
 
+       if (ip->i_fs->fs_ronly)
+               return (EROFS);
        if (uid == -1)
                uid = ip->i_uid;
        if (gid == -1)
                gid = ip->i_gid;
        if (uid == -1)
                uid = ip->i_uid;
        if (gid == -1)
                gid = ip->i_gid;
+       if (uid != ip->i_uid && !suser())
+               return (u.u_error);
+       if (gid != ip->i_gid && !groupmember((gid_t)gid) && !suser())
+               return (u.u_error);
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
 #ifdef QUOTA
        if (ip->i_uid == uid)           /* this just speeds things a little */
                change = 0;
@@ -656,7 +668,7 @@ chown1(ip, uid, gid)
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
        (void) chkdq(ip, change, 1);
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
        (void) chkdq(ip, change, 1);
-       (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
+       (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
        return (u.u_error);             /* should == 0 ALWAYS !! */
 #else
        return (0);
        return (u.u_error);             /* should == 0 ALWAYS !! */
 #else
        return (0);
@@ -674,6 +686,11 @@ utimes()
 
        if ((ip = owner(uap->fname, FOLLOW)) == NULL)
                return;
 
        if ((ip = owner(uap->fname, FOLLOW)) == NULL)
                return;
+       if (ip->i_fs->fs_ronly) {
+               u.u_error = EROFS;
+               iput(ip);
+               return;
+       }
        u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
        if (u.u_error == 0) {
                ip->i_flag |= IACC|IUPD|ICHG;
        u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
        if (u.u_error == 0) {
                ip->i_flag |= IACC|IUPD|ICHG;
@@ -698,7 +715,7 @@ truncate()
 {
        struct a {
                char    *fname;
 {
        struct a {
                char    *fname;
-               u_long  length;
+               off_t   length;
        } *uap = (struct a *)u.u_ap;
        struct inode *ip;
        register struct nameidata *ndp = &u.u_nd;
        } *uap = (struct a *)u.u_ap;
        struct inode *ip;
        register struct nameidata *ndp = &u.u_nd;
@@ -715,7 +732,7 @@ truncate()
                u.u_error = EISDIR;
                goto bad;
        }
                u.u_error = EISDIR;
                goto bad;
        }
-       itrunc(ip, uap->length);
+       itrunc(ip, (u_long)uap->length);
 bad:
        iput(ip);
 }
 bad:
        iput(ip);
 }
@@ -727,7 +744,7 @@ ftruncate()
 {
        struct a {
                int     fd;
 {
        struct a {
                int     fd;
-               u_long  length;
+               off_t   length;
        } *uap = (struct a *)u.u_ap;
        struct inode *ip;
        struct file *fp;
        } *uap = (struct a *)u.u_ap;
        struct inode *ip;
        struct file *fp;
@@ -741,7 +758,7 @@ ftruncate()
        }
        ip = (struct inode *)fp->f_data;
        ILOCK(ip);
        }
        ip = (struct inode *)fp->f_data;
        ILOCK(ip);
-       itrunc(ip, uap->length);
+       itrunc(ip, (u_long)uap->length);
        IUNLOCK(ip);
 }
 
        IUNLOCK(ip);
 }
 
@@ -761,6 +778,8 @@ fsync()
                return;
        ip = (struct inode *)fp->f_data;
        ILOCK(ip);
                return;
        ip = (struct inode *)fp->f_data;
        ILOCK(ip);
+       if (fp->f_flag&FWRITE)
+               ip->i_flag |= ICHG;
        syncip(ip);
        IUNLOCK(ip);
 }
        syncip(ip);
        IUNLOCK(ip);
 }
@@ -922,6 +941,17 @@ rename()
                 */
                if (xp->i_number == ip->i_number)
                        goto bad;
                 */
                if (xp->i_number == ip->i_number)
                        goto bad;
+               /*
+                * If the parent directory is "sticky", then the user must
+                * own the parent directory, or the destination of the rename,
+                * otherwise the destination may not be changed (except by
+                * root). This implements append-only directories.
+                */
+               if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
+                   u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
+                       error = EPERM;
+                       goto bad;
+               }
                /*
                 * Target must be empty if a directory
                 * and have no links to it.
                /*
                 * Target must be empty if a directory
                 * and have no links to it.
@@ -976,7 +1006,10 @@ rename()
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = uap->from;
        xp = namei(ndp);
        ndp->ni_segflg = UIO_USERSPACE;
        ndp->ni_dirp = uap->from;
        xp = namei(ndp);
-       dp = ndp->ni_pdir;
+       if (xp != NULL)
+               dp = ndp->ni_pdir;
+       else
+               dp = NULL;
        /*
         * Insure that the directory entry still exists and has not
         * changed while the new name has been entered. If the source is
        /*
         * Insure that the directory entry still exists and has not
         * changed while the new name has been entered. If the source is
@@ -987,9 +1020,9 @@ rename()
         * The IRENAME flag insures that it cannot be moved by another
         * rename.
         */
         * The IRENAME flag insures that it cannot be moved by another
         * rename.
         */
-       if (dp == NULL || xp != ip) {
+       if (xp != ip) {
                if (doingdirectory)
                if (doingdirectory)
-                       panic("rename: lost entry");
+                       panic("rename: lost dir entry");
        } else {
                /*
                 * If the source is a directory with a
        } else {
                /*
                 * If the source is a directory with a
@@ -1080,7 +1113,7 @@ maknode(mode, ndp)
        ip->i_nlink = 1;
        ip->i_uid = u.u_uid;
        ip->i_gid = pdir->i_gid;
        ip->i_nlink = 1;
        ip->i_uid = u.u_uid;
        ip->i_gid = pdir->i_gid;
-       if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
+       if (ip->i_mode & ISGID && !groupmember(ip->i_gid) && !suser())
                ip->i_mode &= ~ISGID;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
                ip->i_mode &= ~ISGID;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
@@ -1189,6 +1222,10 @@ mkdir()
                dp->i_flag |= ICHG;
                goto bad;
        }
                dp->i_flag |= ICHG;
                goto bad;
        }
+       if (DIRBLKSIZ > ip->i_fs->fs_fsize)
+               panic("mkdir: blksize");     /* XXX - should grow with bmap() */
+       else
+               ip->i_size = DIRBLKSIZ;
        /*
         * Directory all set up, now
         * install the entry for it in
        /*
         * Directory all set up, now
         * install the entry for it in