minix/lib/libpuffs/protect.c
Thomas Veerman 490e0de548 Import librefuse and libpuffs
Import libpuffs and our port of libpuffs. The port was done as part of
GSoC 2011 FUSE project, done by Evgeniy Ivanov. The librefuse import
did not require any porting efforts. Libpuffs has been modified to
understand our VFS-FS protocol and translate between that and PUFFS. As
an example that it works, fuse-ntfs-3g from pkgsrc can be compiled and
used to mount ntfs partitions:
mount -t ntfs-3g <device> <mountpoint>

FUSE only works with the asynchronous version of VFS. See <docs/UPDATING> on
how to run AVFS.

This patch further includes some changes to mount(1) and mount(2) so it's
possible to use file systems provided by pkgsrc (note: manual modifications
to /etc/system.conf are still needed. There has been made an exception for
fuse-ntfs-3g, so it already as an entry).
2011-11-14 11:53:05 +00:00

146 lines
4.1 KiB
C

/* Created (MFS based):
* June 2011 (Evgeniy Ivanov)
*/
#include "fs.h"
#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
FORWARD _PROTOTYPE( int in_group, (gid_t grp) );
/*===========================================================================*
* fs_chmod *
*===========================================================================*/
PUBLIC int fs_chmod()
{
/* Perform the chmod(name, mode) system call. */
int r;
struct puffs_node *pn;
mode_t mode;
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
mode = (mode_t) fs_m_in.REQ_MODE;
if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL)
return(EINVAL);
puffs_vattr_null(&va);
/* Clear setgid bit if file is not in caller's grp */
va.va_mode = (pn->pn_va.va_mode & ~ALL_MODES) | (mode & ALL_MODES);
va.va_ctime.tv_nsec = 0;
va.va_ctime.tv_sec = clock_time();
if (global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr) != 0)
return(EINVAL);
/* Return full new mode to caller. */
fs_m_out.RES_MODE = pn->pn_va.va_mode;
return(OK);
}
/*===========================================================================*
* fs_chown *
*===========================================================================*/
PUBLIC int fs_chown()
{
int r;
struct puffs_node *pn;
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.REQ_INODE_NR)) == NULL)
return(EINVAL);
/* Not permitted to change the owner of a file on a read-only file sys. */
if (!is_readonly_fs) {
puffs_vattr_null(&va);
va.va_uid = fs_m_in.REQ_UID;
va.va_gid = fs_m_in.REQ_GID;
va.va_mode = pn->pn_va.va_mode & ~(I_SET_UID_BIT | I_SET_GID_BIT);
va.va_ctime.tv_nsec = 0;
va.va_ctime.tv_sec = clock_time();
if (global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr) != 0)
return(EINVAL);
}
/* Update caller on current mode, as it may have changed. */
fs_m_out.RES_MODE = pn->pn_va.va_mode;
return(OK);
}
/*===========================================================================*
* forbidden *
*===========================================================================*/
PUBLIC int forbidden(register struct puffs_node *pn, mode_t access_desired)
{
/* Given a pointer to an pnode, 'pn', 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 mode_t bits, perm_bits;
int r, shift;
/* Isolate the relevant rwx bits from the mode. */
bits = pn->pn_va.va_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 == pn->pn_va.va_uid) shift = 6; /* owner */
else if (caller_gid == pn->pn_va.va_gid) shift = 3; /* group */
else if (in_group(pn->pn_va.va_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 = is_readonly_fs ? EROFS : OK;
}
}
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);
}