diff --git a/source3/modules/vfs_worm.c b/source3/modules/vfs_worm.c index 0d17bbbc814..4abb25d12e8 100644 --- a/source3/modules/vfs_worm.c +++ b/source3/modules/vfs_worm.c @@ -82,6 +82,29 @@ static bool is_readonly(vfs_handle_struct *handle, return true; } +out: + return false; +} +static bool fsp_is_readonly(vfs_handle_struct *handle, files_struct *fsp) +{ + double age; + struct worm_config_data *config = NULL; + + SMB_VFS_HANDLE_GET_DATA(handle, + config, + struct worm_config_data, + return true); + + if (!VALID_STAT(fsp->fsp_name->st)) { + goto out; + } + + age = timespec_elapsed(&fsp->fsp_name->st.st_ex_ctime); + + if (age > config->grace_period) { + return true; + } + out: return false; } @@ -135,9 +158,189 @@ static NTSTATUS vfs_worm_create_file(vfs_handle_struct *handle, return NT_STATUS_OK; } +static int vfs_worm_openat(vfs_handle_struct *handle, + const struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + files_struct *fsp, + const struct vfs_open_how *how) +{ + if (is_readonly(handle, smb_fname) && + (fsp->access_mask & write_access_flags)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, how); +} + +static int vfs_worm_fntimes(vfs_handle_struct *handle, + files_struct *fsp, + struct smb_file_time *ft) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft); +} + +static int vfs_worm_fchmod(vfs_handle_struct *handle, + files_struct *fsp, + mode_t mode) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode); +} + +static int vfs_worm_fchown(vfs_handle_struct *handle, + files_struct *fsp, + uid_t uid, + gid_t gid) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid); +} + +static int vfs_worm_renameat(vfs_handle_struct *handle, + files_struct *srcfsp, + const struct smb_filename *smb_fname_src, + files_struct *dstfsp, + const struct smb_filename *smb_fname_dst) +{ + if (is_readonly(handle, smb_fname_src)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_RENAMEAT( + handle, srcfsp, smb_fname_src, dstfsp, smb_fname_dst); +} + +static int vfs_worm_fsetxattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name, + const void *value, + size_t size, + int flags) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags); +} + +static int vfs_worm_fremotexattr(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name); +} + +static int vfs_worm_unlinkat(vfs_handle_struct *handle, + struct files_struct *dirfsp, + const struct smb_filename *smb_fname, + int flags) +{ + struct smb_filename *full_fname = NULL; + bool readonly; + + full_fname = full_path_from_dirfsp_atname(talloc_tos(), + dirfsp, + smb_fname); + if (full_fname == NULL) { + return -1; + } + + readonly = is_readonly(handle, full_fname); + + TALLOC_FREE(full_fname); + + if (readonly) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_UNLINKAT(handle, dirfsp, smb_fname, flags); +} + +static NTSTATUS vfs_worm_fset_dos_attributes(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32_t dosmode) +{ + if (fsp_is_readonly(handle, fsp)) { + return NT_STATUS_ACCESS_DENIED; + } + + return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode); +} + +static NTSTATUS vfs_worm_fset_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, + uint32_t security_info_sent, + const struct security_descriptor *psd) +{ + if (fsp_is_readonly(handle, fsp)) { + return NT_STATUS_ACCESS_DENIED; + } + + return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); +} + +static int vfs_worm_sys_acl_set_fd(vfs_handle_struct *handle, + struct files_struct *fsp, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl); +} + +static int vfs_worm_sys_acl_delete_def_fd(vfs_handle_struct *handle, + struct files_struct *fsp) +{ + if (fsp_is_readonly(handle, fsp)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FD(handle, fsp); +} + static struct vfs_fn_pointers vfs_worm_fns = { .connect_fn = vfs_worm_connect, .create_file_fn = vfs_worm_create_file, + .openat_fn = vfs_worm_openat, + .fntimes_fn = vfs_worm_fntimes, + .fchmod_fn = vfs_worm_fchmod, + .fchown_fn = vfs_worm_fchown, + .renameat_fn = vfs_worm_renameat, + .fsetxattr_fn = vfs_worm_fsetxattr, + .fremovexattr_fn = vfs_worm_fremotexattr, + .unlinkat_fn = vfs_worm_unlinkat, + .fset_dos_attributes_fn = vfs_worm_fset_dos_attributes, + .fset_nt_acl_fn = vfs_worm_fset_nt_acl, + .sys_acl_set_fd_fn = vfs_worm_sys_acl_set_fd, + .sys_acl_delete_def_fd_fn = vfs_worm_sys_acl_delete_def_fd, }; static_decl_vfs;