/dev/fd driver
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
index 501961f..205d5c2 100644 (file)
@@ -1,4 +1,10 @@
-/*     vfs_syscalls.c  6.17    85/03/19        */
+/*
+ * 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.
+ *
+ *     @(#)vfs_syscalls.c      7.6 (Berkeley) %G%
+ */
 
 #include "param.h"
 #include "systm.h"
 
 #include "param.h"
 #include "systm.h"
@@ -35,8 +41,9 @@ chdir()
 chroot()
 {
 
 chroot()
 {
 
-       if (suser())
-               chdirec(&u.u_rdir);
+       if (u.u_error = suser(u.u_cred, &u.u_acflag))
+               return;
+       chdirec(&u.u_rdir);
 }
 
 /*
 }
 
 /*
@@ -113,14 +120,12 @@ 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) {
@@ -131,16 +136,15 @@ copen(mode, arg, fname)
                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;
                }
@@ -148,7 +152,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;
@@ -167,9 +171,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);
@@ -177,23 +178,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--;
 }
 
 /*
 }
 
 /*
@@ -209,7 +209,7 @@ mknod()
        } *uap = (struct a *)u.u_ap;
        register struct nameidata *ndp = &u.u_nd;
 
        } *uap = (struct a *)u.u_ap;
        register struct nameidata *ndp = &u.u_nd;
 
-       if (!suser())
+       if (u.u_error = suser(u.u_cred, &u.u_acflag))
                return;
        ndp->ni_nameiop = CREATE;
        ndp->ni_segflg = UIO_USERSPACE;
                return;
        ndp->ni_nameiop = CREATE;
        ndp->ni_segflg = UIO_USERSPACE;
@@ -261,7 +261,13 @@ link()
        ip = namei(ndp);        /* well, this routine is doomed anyhow */
        if (ip == NULL)
                return;
        ip = namei(ndp);        /* well, this routine is doomed anyhow */
        if (ip == NULL)
                return;
-       if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
+       if ((ip->i_mode&IFMT) == IFDIR &&
+           (u.u_error = suser(u.u_cred, &u.u_acflag))) {
+               iput(ip);
+               return;
+       }
+       if (ip->i_nlink == LINK_MAX - 1) {
+               u.u_error = EMLINK;
                iput(ip);
                return;
        }
                iput(ip);
                return;
        }
@@ -332,7 +338,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);
 }
@@ -357,7 +364,8 @@ unlink()
        if (ip == NULL)
                return;
        dp = ndp->ni_pdir;
        if (ip == NULL)
                return;
        dp = ndp->ni_pdir;
-       if ((ip->i_mode&IFMT) == IFDIR && !suser())
+       if ((ip->i_mode&IFMT) == IFDIR &&
+           (u.u_error = suser(u.u_cred, &u.u_acflag)))
                goto out;
        /*
         * Don't unlink a mounted file.
                goto out;
        /*
         * Don't unlink a mounted file.
@@ -514,10 +522,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;
@@ -536,7 +545,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,10 +565,11 @@ fchmod()
        if (fp == NULL)
                return;
        ip = (struct inode *)fp->f_data;
        if (fp == NULL)
                return;
        ip = (struct inode *)fp->f_data;
-       if (u.u_uid != ip->i_uid && !suser())
+       if (u.u_uid != ip->i_uid &&
+           (u.u_error = suser(u.u_cred, &u.u_acflag)))
                return;
        ILOCK(ip);
                return;
        ILOCK(ip);
-       chmod1(ip, uap->fmode);
+       u.u_error = chmod1(ip, uap->fmode);
        IUNLOCK(ip);
 }
 
        IUNLOCK(ip);
 }
 
@@ -572,9 +582,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;
        }
@@ -582,6 +595,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);
 }
 
 /*
 }
 
 /*
@@ -595,8 +609,13 @@ chown()
                int     uid;
                int     gid;
        } *uap = (struct a *)u.u_ap;
                int     uid;
                int     gid;
        } *uap = (struct a *)u.u_ap;
+       register struct nameidata *ndp = &u.u_nd;
 
 
-       if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL)
+       ndp->ni_nameiop = LOOKUP | NOFOLLOW;
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = uap->fname;
+       ip = namei(ndp);
+       if (ip == 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);
@@ -619,8 +638,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);
@@ -638,10 +655,21 @@ 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 we don't own the file, are trying to change the owner
+        * of the file, or are not a member of the target group,
+        * the caller must be superuser or the call fails.
+        */
+       if ((u.u_uid != ip->i_uid || uid != ip->i_uid ||
+           !groupmember((gid_t)gid)) &&
+           (u.u_error = suser(u.u_cred, &u.u_acflag)))
+               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;
@@ -659,7 +687,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);
@@ -677,6 +705,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;
@@ -701,7 +734,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;
@@ -718,7 +751,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);
 }
@@ -730,7 +763,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;
@@ -744,7 +777,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);
 }
 
@@ -764,6 +797,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);
 }
@@ -925,6 +960,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.
@@ -1086,7 +1132,8 @@ 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) &&
+           (u.u_error = suser(u.u_cred, &u.u_acflag)))
                ip->i_mode &= ~ISGID;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);
                ip->i_mode &= ~ISGID;
 #ifdef QUOTA
        ip->i_dquot = inoquota(ip);