minix/servers/mfs/protect.c
Thomas Veerman 958b25be50 - Introduce support for sticky bit.
- Revise VFS-FS protocol and update VFS/MFS/ISOFS accordingly.
- Clean up MFS by removing old, dead code (backwards compatibility is broken by
  the new VFS-FS protocol, anyway) and rewrite other parts. Also, make sure all
  functions have proper banners and prototypes.
- VFS should always provide a (syntactically) valid path to the FS; no need for
  the FS to do sanity checks when leaving/entering mount points.
- Fix several bugs in MFS:
  - Several path lookup bugs in MFS.
  - A link can be too big for the path buffer.
  - A mountpoint can become inaccessible when the creation of a new inode
    fails, because the inode already exists and is a mountpoint.
- Introduce support for supplemental groups.
- Add test 46 to test supplemental group functionality (and removed obsolete
  suppl. tests from test 2).
- Clean up VFS (not everything is done yet).
- ISOFS now opens device read-only. This makes the -r flag in the mount command
  unnecessary (but will still report to be mounted read-write).
- Introduce PipeFS. PipeFS is a new FS that handles all anonymous and
  named pipes. However, named pipes still reside on the (M)FS, as they are part
  of the file system on disk. To make this work VFS now has a concept of
  'mapped' inodes, which causes read, write, truncate and stat requests to be
  redirected to the mapped FS, and all other requests to the original FS.
2009-12-20 20:27:14 +00:00

152 lines
4.3 KiB
C

#include "fs.h"
#include <unistd.h>
#include <minix/callnr.h>
#include "buf.h"
#include "inode.h"
#include "super.h"
#include <minix/vfsif.h>
FORWARD _PROTOTYPE( in_group, (gid_t grp) );
/*===========================================================================*
* fs_chmod *
*===========================================================================*/
PUBLIC int fs_chmod()
{
/* Perform the chmod(name, mode) system call. */
register struct inode *rip;
register int r;
/* Temporarily open the file. */
if( (rip = get_inode(fs_dev, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
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) | (fs_m_in.REQ_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, fs_m_in.REQ_INODE_NR)) == NIL_INODE)
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 = fs_m_in.REQ_UID;
rip->i_gid = 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 struct super_block *sp;
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);
}