/* struct vnop_access_args { struct vnode *a_vp; #if VOP_ACCESS_TAKES_ACCMODE_T accmode_t a_accmode; #else int a_mode; #endif struct ucred *a_cred; struct thread *a_td; }; */ static int fuse_vnop_access(struct vop_access_args *ap) { struct vnode *vp = ap->a_vp; int accmode = ap->a_accmode; struct ucred *cred = ap->a_cred; struct fuse_access_param facp; struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); int err; FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); if (fuse_isdeadfs(vp)) { if (vnode_isvroot(vp)) { return 0; } return ENXIO; } if (!(data->dataflags & FSESS_INITED)) { if (vnode_isvroot(vp)) { if (priv_check_cred(cred, PRIV_VFS_ADMIN, 0) || (fuse_match_cred(data->daemoncred, cred) == 0)) { return 0; } } return EBADF; } if (vnode_islnk(vp)) { return 0; } bzero(&facp, sizeof(facp)); err = fuse_internal_access(vp, accmode, &facp, ap->a_td, ap->a_cred); FS_DEBUG2G("err=%d accmode=0x%x\n", err, accmode); return err; }
int fuse_internal_access(struct vnode *vp, mode_t mode, struct fuse_access_param *facp, struct thread *td, struct ucred *cred) { int err = 0; uint32_t mask = 0; int dataflags; int vtype; struct mount *mp; struct fuse_dispatcher fdi; struct fuse_access_in *fai; struct fuse_data *data; /* NOT YET DONE */ /* * If this vnop gives you trouble, just return 0 here for a lazy * kludge. */ /* return 0;*/ fuse_trace_printf_func(); mp = vnode_mount(vp); vtype = vnode_vtype(vp); data = fuse_get_mpdata(mp); dataflags = data->dataflags; if ((mode & VWRITE) && vfs_isrdonly(mp)) { return EACCES; } /* Unless explicitly permitted, deny everyone except the fs owner. */ if (vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { if (!(dataflags & FSESS_DAEMON_CAN_SPY)) { int denied = fuse_match_cred(data->daemoncred, cred); if (denied) { return EPERM; } } facp->facc_flags |= FACCESS_NOCHECKSPY; } if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { return 0; } if (((vtype == VREG) && (mode & VEXEC))) { #ifdef NEED_MOUNT_ARGUMENT_FOR_THIS /* Let the kernel handle this through open / close heuristics.*/ return ENOTSUP; #else /* Let the kernel handle this. */ return 0; #endif } if (!fsess_isimpl(mp, FUSE_ACCESS)) { /* Let the kernel handle this. */ return 0; } if (dataflags & FSESS_DEFAULT_PERMISSIONS) { /* Let the kernel handle this. */ return 0; } if ((mode & VADMIN) != 0) { err = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); if (err) { return err; } } if ((mode & (VWRITE | VAPPEND | VADMIN)) != 0) { mask |= W_OK; } if ((mode & VREAD) != 0) { mask |= R_OK; } if ((mode & VEXEC) != 0) { mask |= X_OK; } bzero(&fdi, sizeof(fdi)); fdisp_init(&fdi, sizeof(*fai)); fdisp_make_vp(&fdi, FUSE_ACCESS, vp, td, cred); fai = fdi.indata; fai->mask = F_OK; fai->mask |= mask; err = fdisp_wait_answ(&fdi); fdisp_destroy(&fdi); if (err == ENOSYS) { fsess_set_notimpl(mp, FUSE_ACCESS); err = 0; } return err; }
__private_extern__ int fuse_internal_access(vnode_t vp, int action, vfs_context_t context, struct fuse_access_param *facp) { int err = 0; int default_error = 0; uint32_t mask = 0; int dataflags; mount_t mp; struct fuse_dispatcher fdi; struct fuse_access_in *fai; struct fuse_data *data; fuse_trace_printf_func(); mp = vnode_mount(vp); data = fuse_get_mpdata(mp); dataflags = data->dataflags; /* Allow for now; let checks be handled inline later. */ if (fuse_isdeferpermissions_mp(mp)) { return 0; } if (facp->facc_flags & FACCESS_FROM_VNOP) { default_error = ENOTSUP; } /* * (action & KAUTH_VNODE_GENERIC_WRITE_BITS) on a read-only file system * would have been handled by higher layers. */ if (!fuse_implemented(data, FSESS_NOIMPLBIT(ACCESS))) { return default_error; } /* Unless explicitly permitted, deny everyone except the fs owner. */ if (!vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { if (!(dataflags & FSESS_ALLOW_OTHER)) { int denied = fuse_match_cred(data->daemoncred, vfs_context_ucred(context)); if (denied) { return EPERM; } } facp->facc_flags |= FACCESS_NOCHECKSPY; } if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { return default_error; } if (vnode_isdir(vp)) { if (action & (KAUTH_VNODE_LIST_DIRECTORY | KAUTH_VNODE_READ_EXTATTRIBUTES)) { mask |= R_OK; } if (action & (KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY | KAUTH_VNODE_DELETE_CHILD)) { mask |= W_OK; } if (action & KAUTH_VNODE_SEARCH) { mask |= X_OK; } } else { if (action & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_EXTATTRIBUTES)) { mask |= R_OK; } if (action & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA)) { mask |= W_OK; } if (action & KAUTH_VNODE_EXECUTE) { mask |= X_OK; } } if (action & (KAUTH_VNODE_WRITE_ATTRIBUTES | KAUTH_VNODE_WRITE_EXTATTRIBUTES | KAUTH_VNODE_WRITE_SECURITY)) { mask |= W_OK; } bzero(&fdi, sizeof(fdi)); fdisp_init(&fdi, sizeof(*fai)); fdisp_make_vp(&fdi, FUSE_ACCESS, vp, context); fai = fdi.indata; fai->mask = F_OK; fai->mask |= mask; if (!(err = fdisp_wait_answ(&fdi))) { fuse_ticket_drop(fdi.tick); } if (err == ENOSYS) { /* * Make sure we don't come in here again. */ vfs_clearauthopaque(mp); fuse_clear_implemented(data, FSESS_NOIMPLBIT(ACCESS)); err = default_error; } if (err == ENOENT) { const char *vname = NULL; #if M_MACFUSE_ENABLE_UNSUPPORTED vname = vnode_getname(vp); #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ IOLog("MacFUSE: disappearing vnode %p (name=%s type=%d action=%x)\n", vp, (vname) ? vname : "?", vnode_vtype(vp), action); #if M_MACFUSE_ENABLE_UNSUPPORTED if (vname) { vnode_putname(vname); } #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ /* * On 10.4, I think I can get Finder to lock because of /.Trashes/<uid> * unless I use REVOKE_NONE here. */ #if M_MACFUSE_ENABLE_INTERIM_FSNODE_LOCK && !M_MACFUSE_ENABLE_HUGE_LOCK fuse_biglock_unlock(data->biglock); #endif fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT); #if M_MACFUSE_ENABLE_INTERIM_FSNODE_LOCK && !M_MACFUSE_ENABLE_HUGE_LOCK fuse_biglock_lock(data->biglock); #endif } return err; }