int smbfs_access(void *v) { struct vop_access_args /* { struct vnode *a_vp; int a_mode; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); u_int acc_mode = ap->a_mode; int error; #ifdef SMB_VNODE_DEBUG struct smbmount *smp = VTOSMBFS(vp); #endif SMBVDEBUG("file '%.*s', node mode=%o, acc mode=%x\n", (int) np->n_nmlen, np->n_name, (vp->v_type == VDIR) ? smp->sm_args.dir_mode : smp->sm_args.file_mode, acc_mode); error = smbfs_check_possible(vp, np, acc_mode); if (error) return error; error = smbfs_check_permitted(vp, np, acc_mode, ap->a_cred); return error; }
int smbfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag) { struct smbmount *smp = VTOSMBFS(vp); struct smbnode *np = VTOSMB(vp); struct smb_cred *scred; struct thread *td; int error = 0; if (vp->v_type != VREG) { SMBERROR("vn types other than VREG unsupported !\n"); return EIO; } SMBVDEBUG("ofs=%jd,resid=%zd\n", (intmax_t)uiop->uio_offset, uiop->uio_resid); if (uiop->uio_offset < 0) return EINVAL; /* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize) return (EFBIG);*/ td = uiop->uio_td; if (ioflag & (IO_APPEND | IO_SYNC)) { if (np->n_flag & NMODIFIED) { smbfs_attr_cacheremove(vp); error = smbfs_vinvalbuf(vp, td); if (error) return error; } if (ioflag & IO_APPEND) { #ifdef notyet /* * File size can be changed by another client */ smbfs_attr_cacheremove(vp); error = VOP_GETATTR(vp, &vattr, cred); if (error) return (error); #endif uiop->uio_offset = np->n_size; } } if (uiop->uio_resid == 0) return 0; if (vn_rlimit_fsize(vp, uiop, td)) return (EFBIG); scred = smbfs_malloc_scred(); smb_makescred(scred, td, cred); error = smb_write(smp->sm_share, np->n_fid, uiop, scred); smbfs_free_scred(scred); SMBVDEBUG("after: ofs=%jd,resid=%zd\n", (intmax_t)uiop->uio_offset, uiop->uio_resid); if (!error) { if (uiop->uio_offset > np->n_size) { np->n_size = uiop->uio_offset; vnode_pager_setsize(vp, np->n_size); } } return error; }
int smbfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag) { struct thread *td; struct smbmount *smp = VTOSMBFS(vp); struct smbnode *np = VTOSMB(vp); struct smb_cred scred; int error = 0; if (vp->v_type != VREG) { SMBERROR("vn types other than VREG unsupported !\n"); return EIO; } SMBVDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid); if (uiop->uio_offset < 0) return EINVAL; td = uiop->uio_td; if (ioflag & (IO_APPEND | IO_SYNC)) { if (np->n_flag & NMODIFIED) { smbfs_attr_cacheremove(vp); error = smbfs_vinvalbuf(vp, V_SAVE, 1); if (error) return error; } if (ioflag & IO_APPEND) { #if 0 /* notyet */ /* * File size can be changed by another client */ smbfs_attr_cacheremove(vp); error = VOP_GETATTR(vp, &vattr); if (error) return (error); #endif uiop->uio_offset = np->n_size; } } if (uiop->uio_resid == 0) return 0; if (td->td_proc && uiop->uio_offset + uiop->uio_resid > td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) { lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ); return EFBIG; } smb_makescred(&scred, td, cred); error = smb_write(smp->sm_share, np->n_fid, uiop, &scred); SMBVDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid); if (!error) { if (uiop->uio_offset > np->n_size) { np->n_size = uiop->uio_offset; vnode_pager_setsize(vp, np->n_size); } } return error; }
static int smbfs_check_permitted(struct vnode *vp, struct smbnode *np, mode_t mode, kauth_cred_t cred) { struct smbmount *smp = VTOSMBFS(vp); mode_t file_mode = (vp->v_type == VDIR) ? smp->sm_args.dir_mode : smp->sm_args.file_mode; return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type, file_mode), vp, NULL, genfs_can_access(vp->v_type, file_mode, smp->sm_args.uid, smp->sm_args.gid, mode, cred)); }
int smbfs_setattr(void *v) { struct vop_setattr_args /* { struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; } */ *ap = v; struct lwp *l = curlwp; struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); struct vattr *vap = ap->a_vap; struct timespec *mtime, *atime; struct smb_cred scred; struct smb_share *ssp = np->n_mount->sm_share; struct smb_vc *vcp = SSTOVC(ssp); u_quad_t tsize = 0; int isreadonly, doclose, error = 0; SMBVDEBUG0("\n"); if (vap->va_flags != VNOVAL) return EOPNOTSUPP; isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); /* * Disallow write attempts if the filesystem is mounted read-only. */ if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) && isreadonly) return EROFS; smb_makescred(&scred, l, ap->a_cred); if (vap->va_size != VNOVAL) { switch (vp->v_type) { case VDIR: return EISDIR; case VREG: break; default: return EINVAL; }; if (isreadonly) return EROFS; doclose = 0; tsize = np->n_size; np->n_size = vap->va_size; uvm_vnp_setsize(vp, vap->va_size); if ((np->n_flag & NOPEN) == 0) { error = smbfs_smb_open(np, SMB_SM_DENYNONE|SMB_AM_OPENRW, &scred); if (error == 0) doclose = 1; } if (error == 0) error = smbfs_smb_setfsize(np, vap->va_size, &scred); if (doclose) smbfs_smb_close(ssp, np->n_fid, NULL, &scred); if (error) { np->n_size = tsize; uvm_vnp_setsize(vp, tsize); return (error); } } mtime = atime = NULL; if (vap->va_mtime.tv_sec != VNOVAL) mtime = &vap->va_mtime; if (vap->va_atime.tv_sec != VNOVAL) atime = &vap->va_atime; if (mtime != atime) { error = kauth_authorize_vnode(ap->a_cred, KAUTH_VNODE_WRITE_TIMES, ap->a_vp, NULL, genfs_can_chtimes(ap->a_vp, vap->va_vaflags, VTOSMBFS(vp)->sm_args.uid, ap->a_cred)); if (error) return (error); #if 0 if (mtime == NULL) mtime = &np->n_mtime; if (atime == NULL) atime = &np->n_atime; #endif /* * If file is opened, then we can use handle based calls. * If not, use path based ones. */ if ((np->n_flag & NOPEN) == 0) { if (vcp->vc_flags & SMBV_WIN95) { error = VOP_OPEN(vp, FWRITE, ap->a_cred); if (!error) { /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); VOP_GETATTR(vp, &vattr, ap->a_cred);*/ if (mtime) np->n_mtime = *mtime; VOP_CLOSE(vp, FWRITE, ap->a_cred); } } else if (SMB_CAPS(vcp) & SMB_CAP_NT_SMBS) { error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred); } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); } else { error = smbfs_smb_setpattr(np, 0, mtime, &scred); } } else { if (SMB_CAPS(vcp) & SMB_CAP_NT_SMBS) { error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { error = smbfs_smb_setftime(np, mtime, atime, &scred); } else { /* * XXX I have no idea how to handle this for core * level servers. The possible solution is to * update mtime after file is closed. */ } } } /* * Invalidate attribute cache in case if server doesn't set * required attributes. */ smbfs_attr_cacheremove(vp); /* invalidate cache */ VOP_GETATTR(vp, vap, ap->a_cred); np->n_mtime.tv_sec = vap->va_mtime.tv_sec; VN_KNOTE(vp, NOTE_ATTRIB); return error; }