#include "fs.h" #include "inode.h" #include "super.h" #include FORWARD _PROTOTYPE( int in_group, (gid_t grp) ); /*===========================================================================* * fs_chmod * *===========================================================================*/ PUBLIC int fs_chmod() { /* Perform the chmod(name, mode) system call. */ register struct inode *rip; mode_t mode; mode = (mode_t) fs_m_in.REQ_MODE; /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* Now make the change. Clear setgid bit if file is not in caller's grp */ rip->i_mode = (rip->i_mode & ~ALL_MODES) | (mode & ALL_MODES); rip->i_update |= CTIME; rip->i_dirt = DIRTY; /* Return full new mode to caller. */ fs_m_out.RES_MODE = rip->i_mode; put_inode(rip); return(OK); } /*===========================================================================* * fs_chown * *===========================================================================*/ PUBLIC int fs_chown() { register struct inode *rip; register int r; /* Temporarily open the file. */ if( (rip = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL) return(EINVAL); /* Not permitted to change the owner of a file on a read-only file sys. */ r = read_only(rip); if (r == OK) { rip->i_uid = (uid_t) fs_m_in.REQ_UID; rip->i_gid = (gid_t) fs_m_in.REQ_GID; rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT); rip->i_update |= CTIME; rip->i_dirt = DIRTY; } /* Update caller on current mode, as it may have changed. */ fs_m_out.RES_MODE = rip->i_mode; put_inode(rip); return(r); } /*===========================================================================* * forbidden * *===========================================================================*/ PUBLIC int forbidden(register struct inode *rip, mode_t access_desired) { /* Given a pointer to an inode, 'rip', and the access desired, determine * if the access is allowed, and if not why not. The routine looks up the * caller's uid in the 'fproc' table. If access is allowed, OK is returned * if it is forbidden, EACCES is returned. */ register struct inode *old_rip = rip; register mode_t bits, perm_bits; int r, shift; /* Isolate the relevant rwx bits from the mode. */ bits = rip->i_mode; if (caller_uid == SU_UID) { /* Grant read and write permission. Grant search permission for * directories. Grant execute permission (for non-directories) if * and only if one of the 'X' bits is set. */ if ( (bits & I_TYPE) == I_DIRECTORY || bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT)) perm_bits = R_BIT | W_BIT | X_BIT; else perm_bits = R_BIT | W_BIT; } else { if (caller_uid == rip->i_uid) shift = 6; /* owner */ else if (caller_gid == rip->i_gid) shift = 3; /* group */ else if (in_group(rip->i_gid) == OK) shift = 3; /* other groups */ else shift = 0; /* other */ perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); } /* If access desired is not a subset of what is allowed, it is refused. */ r = OK; if ((perm_bits | access_desired) != perm_bits) r = EACCES; /* Check to see if someone is trying to write on a file system that is * mounted read-only. */ if (r == OK) if (access_desired & W_BIT) r = read_only(rip); if (rip != old_rip) put_inode(rip); return(r); } /*===========================================================================* * in_group * *===========================================================================*/ PRIVATE int in_group(gid_t grp) { int i; for(i = 0; i < credentials.vu_ngroups; i++) if (credentials.vu_sgroups[i] == grp) return(OK); return(EINVAL); } /*===========================================================================* * read_only * *===========================================================================*/ PUBLIC int read_only(ip) struct inode *ip; /* ptr to inode whose file sys is to be cked */ { /* Check to see if the file system on which the inode 'ip' resides is mounted * read only. If so, return EROFS, else return OK. */ register struct super_block *sp; sp = ip->i_sp; return(sp->s_rd_only ? EROFS : OK); }