The branch, master has been updated via f14a7065690 smbd: move access override for previous versions to the SMB layer via fd4e41144a8 smbd: check for previous versions in check_any_access_fsp() via 02ed99343d1 smbd: use check_any_access_fsp() for all access checks via 995a31c8d4c smbd: replace CHECK_WRITE() macro with calls to check_any_access_fsp() via ee3035218df smbd: set fsp->fsp_flags.can_write to false for access to previous-versions via a0ae45be770 smbd: return correct error when trying to create a hardlink to a VSS file via bf497819e61 smbd: fix check_any_access_fsp() for non-fsa fsps via 96b577c380f smbd: rename check_access_fsp() to check_any_access_fsp() via 76c8fe16bff smbd: set fsp_flags.is_fsa to true on printer file handles via 276c5bd851a smbd: return the correct error in can_rename() via 537eedfe2a7 smbtorture: expand smb2.twrp.write test via c62484bc2c6 s4/libcli/raw: implemement RAW_SFILEINFO_LINK_INFORMATION via 78119edba01 selftest: remove error_inject from shadow_write share from 1047abf3aa3 selftest: let list_servers.NT1 really use NT1 protocol
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit f14a7065690b00e3c6af2c1f0b0aec51c1e0b372 Author: Ralph Boehme <s...@samba.org> Date: Fri Dec 15 11:59:36 2023 +0100 smbd: move access override for previous versions to the SMB layer Doing the previous version access checks and semantics at the SMB layer means we can simplify the shadow_copy2 and remove the kludge. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> Autobuild-User(master): Ralph Böhme <s...@samba.org> Autobuild-Date(master): Mon Jan 8 16:58:26 UTC 2024 on atb-devel-224 commit fd4e41144a819b4403340e4a28664ac586722b41 Author: Ralph Boehme <s...@samba.org> Date: Wed Dec 20 15:09:59 2023 +0100 smbd: check for previous versions in check_any_access_fsp() Now that check_any_access_fsp() is broadly used consistently to restrict access for all modifying operations, we can add a check for previous versions to check_any_access_fsp() and it gets enforced consistently. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 02ed99343d19fd0845531ad99a46b1dd5b8a7a4f Author: Ralph Boehme <s...@samba.org> Date: Wed Dec 20 18:01:57 2023 +0100 smbd: use check_any_access_fsp() for all access checks Replaces the direct access to fsp->access_mask with a call to check_any_access_fsp() which allows doing additional checks if needed. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 995a31c8d4c1789c16bae6b8196f2565d4b1dfdb Author: Ralph Boehme <s...@samba.org> Date: Wed Dec 20 18:32:25 2023 +0100 smbd: replace CHECK_WRITE() macro with calls to check_any_access_fsp() The additional check if fd underlying fd is valid and not -1 should not be done at this place. I actually would prefer an write to fail with EBADF if this happens, as it's likely easier to debug why this happened. These days we should always have a valid fd. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit ee3035218df4cfd68b6aab6825c78f2b85234c6c Author: Ralph Boehme <s...@samba.org> Date: Wed Dec 20 18:03:22 2023 +0100 smbd: set fsp->fsp_flags.can_write to false for access to previous-versions BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit a0ae45be770a13373c148a689b9761f14c4f942c Author: Ralph Boehme <s...@samba.org> Date: Fri Dec 22 11:19:38 2023 +0100 smbd: return correct error when trying to create a hardlink to a VSS file BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit bf497819e61131cfa6469971596af3aa9bd4bb49 Author: Ralph Boehme <s...@samba.org> Date: Thu Dec 21 10:58:09 2023 +0100 smbd: fix check_any_access_fsp() for non-fsa fsps smbd_check_access_rights_fsp() requires *all* rights in access_mask to be granted by the underlying ACL, but the semantics of this function is supposed to grant access if any one of the rights in access_requested is allowed. Fix this by looping over the requested access mask. If smbd_check_access_rights_fsp() returns sucess, mask will be non-null and when assigned to access_granted, the subsequent check will pass, fail otherwise. I'm not doing an early exit on purpose because a subsequent commit adds additional security checks that are done in the subsequent code path common for fsa and non-fsa fsps. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 96b577c380fa914eb1ffa95849c82bdb88aa1ec6 Author: Ralph Boehme <s...@samba.org> Date: Thu Dec 21 10:58:09 2023 +0100 smbd: rename check_access_fsp() to check_any_access_fsp() The semantics of the access check in check_access_fsp() itself is to allow access if *at least* one or more rights of the rights in access_mask are allowed. The name check_any_access_fsp() better reflects this. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 76c8fe16bff36a29fa326355256b50737d04bd85 Author: Ralph Boehme <s...@samba.org> Date: Thu Dec 21 16:27:42 2023 +0100 smbd: set fsp_flags.is_fsa to true on printer file handles Printer file handles went through SMB_VFS_CREATE_FILE() and are network callable, so it makes sense to set this on them. This ensures that check_access_fsp() doesn't take the codepath calling smbd_check_access_rights_fsp(), but just checks the request rights from fsp->access_mask. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 276c5bd851ab6ab818a49d9c47f6b96de8024778 Author: Ralph Boehme <s...@samba.org> Date: Tue Dec 19 13:06:55 2023 +0100 smbd: return the correct error in can_rename() This is what Windows returns for this case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 537eedfe2a79fba2e1f062f14ba7a0c5f8f70a88 Author: Ralph Boehme <s...@samba.org> Date: Fri Dec 15 19:55:23 2023 +0100 smbtorture: expand smb2.twrp.write test Test more modifying operations are blocked and access masks are correct. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit c62484bc2c60ebac42635793d94cb8e62629acbf Author: Ralph Boehme <s...@samba.org> Date: Fri Dec 22 10:40:39 2023 +0100 s4/libcli/raw: implemement RAW_SFILEINFO_LINK_INFORMATION BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit 78119edba013583555069271bb61134c12c2c135 Author: Ralph Boehme <s...@samba.org> Date: Thu Dec 21 19:40:21 2023 +0100 selftest: remove error_inject from shadow_write share Frankly, I can't remember why I added this as part of bug 13688. The goal of the corresponding test is to verify a write on a read-only file handle fails. As the file is opened O_RDONLY, the write will fail anyway and there's no need to inject the error. To make things worse, having the error injected meant we didn't notice when the underlying logic of forcing the open to be done with O_RDONLY was done as O_RDWR, resulting in the write on the handle to succeed. This happened when we introduced reopen_from_fsp(): the initial pathref open of a path with a twrp value was correctly detected and handled by shadow_copy2_openat(). However, when converting the pathref open to a real one via reopen_from_fsp(), shadow_copy2_openat() only sees the magic /proc/fd path and has no way of inferring that this was originating from a prevous version open with a twrp value. Tl;dr: we can just remove this error injection, it is not needed, the correct fix is to implement this in the SMB layer which is done in the subsequent commits. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13688 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> ----------------------------------------------------------------------- Summary of changes: selftest/target/Samba3.pm | 4 +- source3/include/smb_macros.h | 5 - source3/modules/offload_token.c | 7 +- source3/modules/vfs_acl_common.c | 7 +- source3/modules/vfs_nfs4acl_xattr.c | 7 +- source3/modules/vfs_shadow_copy2.c | 30 +---- source3/printing/printspoolss.c | 1 + source3/smbd/dir.c | 5 +- source3/smbd/dosmode.c | 20 +-- source3/smbd/file_access.c | 10 +- source3/smbd/files.c | 3 + source3/smbd/notify.c | 5 +- source3/smbd/open.c | 43 ++++++- source3/smbd/proto.h | 4 +- source3/smbd/smb1_reply.c | 37 +++--- source3/smbd/smb2_flush.c | 7 +- source3/smbd/smb2_getinfo.c | 8 +- source3/smbd/smb2_ioctl_filesys.c | 6 +- source3/smbd/smb2_nttrans.c | 45 ++++--- source3/smbd/smb2_reply.c | 15 ++- source3/smbd/smb2_trans2.c | 80 +++++++++--- source3/smbd/smb2_write.c | 6 +- source4/libcli/raw/rawsetfileinfo.c | 14 +++ source4/torture/smb2/create.c | 245 +++++++++++++++++++++++++++++++++++- 24 files changed, 489 insertions(+), 125 deletions(-) Changeset truncated at 500 lines: diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 0375e913a9d..bfa9fad5ffe 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -3447,9 +3447,7 @@ sub provision($$) [shadow_write] path = $shadow_tstdir comment = previous versions snapshots under mount point - vfs objects = shadow_copy2 streams_xattr error_inject - aio write size = 0 - error_inject:pwrite = EBADF + vfs objects = shadow_copy2 streams_xattr shadow:mountpoint = $shadow_tstdir shadow:fixinodes = yes smbd async dosmode = yes diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index 3a942f9df11..4b3989dce93 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -67,11 +67,6 @@ (fsp_get_io_fd(fsp) != -1) && \ (((fsp)->fsp_flags.can_read))) -#define CHECK_WRITE(fsp) \ - ((fsp)->fsp_flags.can_write && \ - (!(fsp)->fsp_flags.is_pathref) && \ - (fsp_get_io_fd(fsp) != -1)) - #define ERROR_WAS_LOCK_DENIED(status) (NT_STATUS_EQUAL((status), NT_STATUS_LOCK_NOT_GRANTED) || \ NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT) ) diff --git a/source3/modules/offload_token.c b/source3/modules/offload_token.c index 901991daf28..3b71a0028fb 100644 --- a/source3/modules/offload_token.c +++ b/source3/modules/offload_token.c @@ -259,6 +259,8 @@ NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl, files_struct *src_fsp, files_struct *dst_fsp) { + NTSTATUS status; + if (src_fsp->vuid != dst_fsp->vuid) { DBG_INFO("copy chunk handles not in the same session.\n"); return NT_STATUS_ACCESS_DENIED; @@ -317,10 +319,11 @@ NTSTATUS vfs_offload_token_check_handles(uint32_t fsctl, * * A non writable dst handle also doesn't make sense for other fsctls. */ - if (!CHECK_WRITE(dst_fsp)) { + status = check_any_access_fsp(dst_fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { DBG_INFO("dest handle not writable (%s).\n", smb_fname_str_dbg(dst_fsp->fsp_name)); - return NT_STATUS_ACCESS_DENIED; + return status; } /* * - The Open.GrantedAccess of the destination file does not include diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c index 692e776d10c..314fc79a3a6 100644 --- a/source3/modules/vfs_acl_common.c +++ b/source3/modules/vfs_acl_common.c @@ -738,10 +738,13 @@ static NTSTATUS set_underlying_acl(vfs_handle_struct *handle, files_struct *fsp, /* We got access denied here. If we're already root, or we didn't need to do a chown, or the fsp isn't open with WRITE_OWNER access, just return. */ - if (get_current_uid(handle->conn) == 0 || !chown_needed || - !(fsp->access_mask & SEC_STD_WRITE_OWNER)) { + if (get_current_uid(handle->conn) == 0 || !chown_needed) { return NT_STATUS_ACCESS_DENIED; } + status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* * Only allow take-ownership, not give-ownership. That's the way Windows diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c index cecafcf50b8..1fd3519ca02 100644 --- a/source3/modules/vfs_nfs4acl_xattr.c +++ b/source3/modules/vfs_nfs4acl_xattr.c @@ -368,11 +368,14 @@ static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle, } if (get_current_uid(handle->conn) == 0 || - chown_needed == false || - !(fsp->access_mask & SEC_STD_WRITE_OWNER)) + chown_needed == false) { return NT_STATUS_ACCESS_DENIED; } + status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER); + if (!NT_STATUS_IS_OK(status)) { + return status; + } /* * Only allow take-ownership, not give-ownership. That's the way Windows diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index ac87ddac46f..47b0edc72c3 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1556,7 +1556,6 @@ static int shadow_copy2_openat(vfs_handle_struct *handle, struct smb_filename *smb_fname = NULL; time_t timestamp = 0; char *stripped = NULL; - bool is_converted = false; int saved_errno = 0; int ret; bool ok; @@ -1573,12 +1572,11 @@ static int shadow_copy2_openat(vfs_handle_struct *handle, return -1; } - ok = shadow_copy2_strip_snapshot_converted(talloc_tos(), - handle, - smb_fname, - ×tamp, - &stripped, - &is_converted); + ok = shadow_copy2_strip_snapshot(talloc_tos(), + handle, + smb_fname, + ×tamp, + &stripped); if (!ok) { TALLOC_FREE(smb_fname); return -1; @@ -1586,16 +1584,6 @@ static int shadow_copy2_openat(vfs_handle_struct *handle, if (timestamp == 0) { TALLOC_FREE(stripped); TALLOC_FREE(smb_fname); - if (is_converted) { - /* - * Just pave over the user requested mode and use - * O_RDONLY. Later attempts by the client to write on - * the handle will fail in the pwrite() syscall with - * EINVAL which we carefully map to EROFS. In sum, this - * matches Windows behaviour. - */ - how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT); - } return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname_in, @@ -1616,14 +1604,6 @@ static int shadow_copy2_openat(vfs_handle_struct *handle, } TALLOC_FREE(stripped); - /* - * Just pave over the user requested mode and use O_RDONLY. Later - * attempts by the client to write on the handle will fail in the - * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum, - * this matches Windows behaviour. - */ - how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT); - ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, diff --git a/source3/printing/printspoolss.c b/source3/printing/printspoolss.c index 31117a4b743..94404f7682a 100644 --- a/source3/printing/printspoolss.c +++ b/source3/printing/printspoolss.c @@ -244,6 +244,7 @@ NTSTATUS print_spool_open(files_struct *fsp, fsp->sent_oplock_break = NO_BREAK_SENT; fsp->fsp_flags.is_directory = false; fsp->fsp_flags.delete_on_close = false; + fsp->fsp_flags.is_fsa = true; fsp->print_file = pf; diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 800b7221cfd..49c37cbb4d9 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -218,11 +218,12 @@ NTSTATUS dptr_create(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - if (!(fsp->access_mask & SEC_DIR_LIST)) { + status = check_any_access_fsp(fsp, SEC_DIR_LIST); + if (!NT_STATUS_IS_OK(status)) { DBG_INFO("dptr_create: directory %s " "not open for LIST access\n", fsp_str_dbg(fsp)); - return NT_STATUS_ACCESS_DENIED; + return status; } status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 6fbcac40d2e..1472af7d059 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -1076,15 +1076,17 @@ NTSTATUS file_set_sparse(connection_struct *conn, * Windows Server 2008 & 2012 permit FSCTL_SET_SPARSE if any of the * following access flags are granted. */ - if ((fsp->access_mask & (FILE_WRITE_DATA - | FILE_WRITE_ATTRIBUTES - | SEC_FILE_APPEND_DATA)) == 0) { - DEBUG(9,("file_set_sparse: fname[%s] set[%u] " - "access_mask[0x%08X] - access denied\n", - smb_fname_str_dbg(fsp->fsp_name), - sparse, - fsp->access_mask)); - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, + FILE_WRITE_DATA + | FILE_WRITE_ATTRIBUTES + | SEC_FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("fname[%s] set[%u] " + "access_mask[0x%08X] - access denied\n", + smb_fname_str_dbg(fsp->fsp_name), + sparse, + fsp->access_mask); + return status; } if (fsp->fsp_flags.is_directory) { diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c index 9ad9173e49c..9928eb99750 100644 --- a/source3/smbd/file_access.c +++ b/source3/smbd/file_access.c @@ -192,6 +192,7 @@ bool directory_has_default_acl_fsp(struct files_struct *fsp) NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode) { + NTSTATUS status; /* * Only allow delete on close for writable files. */ @@ -220,11 +221,12 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode) * intent. */ - if (!(fsp->access_mask & DELETE_ACCESS)) { - DEBUG(10,("can_set_delete_on_close: file %s delete on " + status = check_any_access_fsp(fsp, DELETE_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("file %s delete on " "close flag set but delete access denied.\n", - fsp_str_dbg(fsp))); - return NT_STATUS_ACCESS_DENIED; + fsp_str_dbg(fsp)); + return status; } /* Don't allow delete on close for non-empty directories. */ diff --git a/source3/smbd/files.c b/source3/smbd/files.c index 48b78dc32c0..6aad76a8a5c 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -2448,6 +2448,9 @@ NTSTATUS dup_file_fsp( to->fsp_flags.can_write = CAN_WRITE(from->conn) && ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0); + if (from->fsp_name->twrp != 0) { + to->fsp_flags.can_write = false; + } to->fsp_flags.modified = from->fsp_flags.modified; to->fsp_flags.is_directory = from->fsp_flags.is_directory; to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind; diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index 399d7800249..156fbf700c3 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -295,8 +295,9 @@ NTSTATUS change_notify_create(struct files_struct *fsp, * Setting a changenotify needs READ/LIST access * on the directory handle. */ - if (!(fsp->access_mask & SEC_DIR_LIST)) { - return NT_STATUS_ACCESS_DENIED; + status = check_any_access_fsp(fsp, SEC_DIR_LIST); + if (!NT_STATUS_IS_OK(status)) { + return status; } if (fsp->notify != NULL) { diff --git a/source3/smbd/open.c b/source3/smbd/open.c index d34d0354ff7..da809196fa4 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1635,6 +1635,9 @@ static NTSTATUS open_file( fsp->fsp_flags.can_write = CAN_WRITE(conn) && ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0); + if (fsp->fsp_name->twrp != 0) { + fsp->fsp_flags.can_write = false; + } fsp->print_file = NULL; fsp->fsp_flags.modified = false; fsp->sent_oplock_break = NO_BREAK_SENT; @@ -3626,7 +3629,8 @@ static int disposition_to_open_flags(uint32_t create_disposition) } static int calculate_open_access_flags(uint32_t access_mask, - uint32_t private_flags) + uint32_t private_flags, + NTTIME twrp) { bool need_write, need_read; @@ -3635,6 +3639,15 @@ static int calculate_open_access_flags(uint32_t access_mask, * mean the same thing under DOS and Unix. */ + if (twrp != 0) { + /* + * Pave over the user requested mode and force O_RDONLY for the + * file handle. Windows allows opening a VSS file with O_RDWR, + * even though actual writes on the handle will fail. + */ + return O_RDONLY; + } + need_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)); if (!need_write) { return O_RDONLY; @@ -3800,6 +3813,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, bool posix_open = False; bool new_file_created = False; bool first_open_attempt = true; + bool is_twrp = (smb_fname_atname->twrp != 0); NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; @@ -3959,6 +3973,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, smb_fname_str_dbg(smb_fname) )); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + if (is_twrp) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } break; case FILE_CREATE: @@ -3974,11 +3991,24 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } return NT_STATUS_OBJECT_NAME_COLLISION; } + if (is_twrp) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } break; case FILE_SUPERSEDE: case FILE_OVERWRITE_IF: + if (is_twrp) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + break; case FILE_OPEN_IF: + if (is_twrp) { + if (!file_existed) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + create_disposition = FILE_OPEN; + } break; default: return NT_STATUS_INVALID_PARAMETER; @@ -4051,7 +4081,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * mean the same thing under DOS and Unix. */ - flags |= calculate_open_access_flags(access_mask, private_flags); + flags |= calculate_open_access_flags(access_mask, + private_flags, + smb_fname->twrp); /* * Currently we only look at FILE_WRITE_THROUGH for create options. @@ -4782,6 +4814,10 @@ static NTSTATUS open_directory(connection_struct *conn, return status; } + if (smb_fname_atname->twrp != 0) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } + status = mkdir_internal(conn, parent_dir_fname, smb_fname_atname, @@ -4810,6 +4846,9 @@ static NTSTATUS open_directory(connection_struct *conn, status = NT_STATUS_OK; info = FILE_WAS_OPENED; } else { + if (smb_fname_atname->twrp != 0) { + return NT_STATUS_MEDIA_WRITE_PROTECTED; + } status = mkdir_internal(conn, parent_dir_fname, smb_fname_atname, diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 2875fcf562b..d18afe3e996 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1060,8 +1060,8 @@ NTSTATUS smb_set_file_disposition_info(connection_struct *conn, files_struct *fsp, struct smb_filename *smb_fname); NTSTATUS refuse_symlink_fsp(const struct files_struct *fsp); -NTSTATUS check_access_fsp(struct files_struct *fsp, - uint32_t access_mask); +NTSTATUS check_any_access_fsp(struct files_struct *fsp, + uint32_t access_requested); uint64_t smb_roundup(connection_struct *conn, uint64_t val); bool samba_private_attr_name(const char *unix_ea_name); NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx, diff --git a/source3/smbd/smb1_reply.c b/source3/smbd/smb1_reply.c index cc1b1311cf1..b2f317a1db9 100644 --- a/source3/smbd/smb1_reply.c +++ b/source3/smbd/smb1_reply.c @@ -3928,8 +3928,9 @@ void reply_writebraw(struct smb_request *req) return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); error_to_writebrawerr(req); END_PROFILE(SMBwritebraw); return; @@ -4159,8 +4160,9 @@ void reply_writeunlock(struct smb_request *req) return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBwriteunlock); return; } @@ -4294,8 +4296,9 @@ void reply_write(struct smb_request *req) return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBwrite); return; } @@ -4573,8 +4576,9 @@ void reply_write_and_X(struct smb_request *req) goto out; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); goto out; } @@ -5285,6 +5289,7 @@ void reply_writeclose(struct smb_request *req) struct timespec mtime; files_struct *fsp; struct lock_struct lock; + NTSTATUS status; START_PROFILE(SMBwriteclose); @@ -5300,8 +5305,9 @@ void reply_writeclose(struct smb_request *req) END_PROFILE(SMBwriteclose); return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBwriteclose); return; } @@ -6091,6 +6097,7 @@ void reply_printwrite(struct smb_request *req) int numtowrite; const char *data; files_struct *fsp; + NTSTATUS status; START_PROFILE(SMBsplwr); @@ -6113,8 +6120,9 @@ void reply_printwrite(struct smb_request *req) return; } - if (!CHECK_WRITE(fsp)) { - reply_nterror(req, NT_STATUS_ACCESS_DENIED); + status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA); + if (!NT_STATUS_IS_OK(status)) { -- Samba Shared Repository