diff --git a/source3/modules/vfs_worm.c b/source3/modules/vfs_worm.c index 3097419..7077fae 100644 --- a/source3/modules/vfs_worm.c +++ b/source3/modules/vfs_worm.c @@ -22,6 +22,58 @@ #include "system/filesys.h" #include "libcli/security/security.h" + +static double timespec_elapsed2(const struct timespec *ts1, + const struct timespec *ts2) +{ + return (ts2->tv_sec - ts1->tv_sec) + + (ts2->tv_nsec - ts1->tv_nsec)*1.0e-9; +} + +static double timespec_elapsed(const struct timespec *ts) +{ + struct timespec ts2 = timespec_current(); + return timespec_elapsed2(ts, &ts2); +} + +static bool is_readonly(vfs_handle_struct *handle, const struct smb_filename *smb_fname) +{ + bool readonly = false; + + if (VALID_STAT(smb_fname->st)) { + double age; + age = timespec_elapsed(&smb_fname->st.st_ex_ctime); + int grace_period = lp_parm_int(SNUM(handle->conn), "worm", + "grace_period", 3600); + if (age > grace_period) { + readonly = true; + } + } + + return readonly; +} + + +const uint32_t write_access_flags = + FILE_WRITE_DATA | FILE_APPEND_DATA | + FILE_WRITE_ATTRIBUTES | DELETE_ACCESS | + WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS; + +static int vfs_worm_ntimes(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + struct smb_file_time *ft) +{ + + bool readonly = is_readonly(handle, smb_fname); + + if (readonly) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft); +} + static NTSTATUS vfs_worm_create_file(vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, @@ -40,47 +92,49 @@ static NTSTATUS vfs_worm_create_file(vfs_handle_struct *handle, files_struct **result, int *pinfo) { - bool readonly = false; - const uint32_t write_access_flags = - FILE_WRITE_DATA | FILE_APPEND_DATA | - FILE_WRITE_ATTRIBUTES | DELETE_ACCESS | - WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS; - NTSTATUS status; - - if (VALID_STAT(smb_fname->st)) { - double age; - age = timespec_elapsed(&smb_fname->st.st_ex_ctime); - if (age > lp_parm_int(SNUM(handle->conn), "worm", - "grace_period", 3600)) { - readonly = true; - } - } + bool readonly = is_readonly(handle, smb_fname); - if (readonly && (access_mask & write_access_flags)) { - return NT_STATUS_ACCESS_DENIED; - } + if (readonly && (access_mask & write_access_flags)) { + return NT_STATUS_ACCESS_DENIED; + } - status = SMB_VFS_NEXT_CREATE_FILE( - handle, req, root_dir_fid, smb_fname, access_mask, - share_access, create_disposition, create_options, - file_attributes, oplock_request, lease, allocation_size, - private_flags, sd, ea_list, result, pinfo); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + NTSTATUS status = SMB_VFS_NEXT_CREATE_FILE( + handle, req, root_dir_fid, smb_fname, access_mask, + share_access, create_disposition, create_options, + file_attributes, oplock_request, allocation_size, + sd, ea_list, result, pinfo); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - /* - * Access via MAXIMUM_ALLOWED_ACCESS? - */ - if (readonly && ((*result)->access_mask & write_access_flags)) { - close_file(req, *result, NORMAL_CLOSE); - return NT_STATUS_ACCESS_DENIED; - } - return NT_STATUS_OK; + /* + * Access via MAXIMUM_ALLOWED_ACCESS? + */ + if (readonly && ((*result)->access_mask & write_access_flags)) { + close_file(req, *result, NORMAL_CLOSE); + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + +static int vfs_worm_open(vfs_handle_struct *handle, + struct smb_filename *smb_fname, + files_struct *fsp, int flags, mode_t mode) +{ + bool readonly = is_readonly(handle, smb_fname); + + if (readonly && (fsp->access_mask & write_access_flags)) { + errno = EACCES; + return -1; + } + + return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); } static struct vfs_fn_pointers vfs_worm_fns = { - .create_file_fn = vfs_worm_create_file, + .create_file_fn = vfs_worm_create_file, + .open_fn = vfs_worm_open, + .ntimes_fn = vfs_worm_ntimes }; NTSTATUS vfs_worm_init(void);