From: Ralph Boehme Date: Wed, 1 Apr 2026 12:04:40 +0000 (+0200) Subject: smbd: ignore FILE_ATTRIBUTE_READONLY for the "MxAC" create context X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=03fa9d035d0bd657eaf46abfd8bedf93681a4338;p=thirdparty%2Fsamba.git smbd: ignore FILE_ATTRIBUTE_READONLY for the "MxAC" create context As much as I dislike adding a boolean parameter to control this behaviour, I don't see a different clean way to do it. Note that I'm not touching the case where the share is realy-only, I just don't want to open that additional can of worms now and instead focus on fixing the FILE_ATTRIBUTE_READONLY case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=16030 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher --- diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 9ffece1fb0c..e6c244cc6c8 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -4552,6 +4552,7 @@ static NTSTATUS fruit_freaddir_attr(struct vfs_handle_struct *handle, status = smbd_calculate_access_mask_fsp(fsp->conn->cwd_fsp, fsp, false, + false, SEC_FLAG_MAXIMUM_ALLOWED, &attr_data->attr_data.aapl.max_access); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c index 7e561814769..9a3da37050a 100644 --- a/source3/smbd/fake_file.c +++ b/source3/smbd/fake_file.c @@ -189,6 +189,7 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn, status = smbd_calculate_access_mask_fsp(conn->cwd_fsp, fsp, false, + false, access_mask, &access_mask); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index adc30a940f1..c7d67e2ed9d 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -182,6 +182,7 @@ NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx, NTSTATUS smbd_calculate_access_mask_fsp(struct files_struct *dirsfp, struct files_struct *fsp, bool use_privs, + bool ignore_readonly, uint32_t access_mask, uint32_t *access_mask_out); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 594ffadfeb8..dcaf208f105 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -432,6 +432,7 @@ static NTSTATUS check_base_file_access(struct files_struct *fsp, status = smbd_calculate_access_mask_fsp(fsp->conn->cwd_fsp, fsp, false, + false, access_mask, &access_mask); if (!NT_STATUS_IS_OK(status)) { @@ -3304,6 +3305,7 @@ static NTSTATUS smbd_calculate_maximum_allowed_access_fsp( struct files_struct *dirfsp, struct files_struct *fsp, bool use_privs, + bool ignore_readonly, uint32_t *p_access_mask) { struct security_descriptor *sd = NULL; @@ -3389,17 +3391,30 @@ static NTSTATUS smbd_calculate_maximum_allowed_access_fsp( *p_access_mask &= ~(FILE_GENERIC_WRITE | DELETE_ACCESS); } + if (ignore_readonly) { + /* + * We end up here when the maximum access mask for the "MxAC" + * create context response is needed. That ignores the read-only + * attribute, cf smbtorture tests + * "smb2.maximum_allowed.read_only_file" and + * "smb2.maximum_allowed.read_only_dir". + */ + goto done; + } + dosattrs = fdos_mode(fsp); if (dosattrs & FILE_ATTRIBUTE_READONLY) { *p_access_mask &= ~(FILE_GENERIC_WRITE | DELETE_ACCESS); } +done: return NT_STATUS_OK; } NTSTATUS smbd_calculate_access_mask_fsp(struct files_struct *dirfsp, struct files_struct *fsp, bool use_privs, + bool ignore_readonly, uint32_t access_mask, uint32_t *access_mask_out) { @@ -3426,6 +3441,7 @@ NTSTATUS smbd_calculate_access_mask_fsp(struct files_struct *dirfsp, dirfsp, fsp, use_privs, + ignore_readonly, &access_mask); if (!NT_STATUS_IS_OK(status)) { @@ -3944,7 +3960,7 @@ static NTSTATUS open_file_ntcreate( } status = smbd_calculate_access_mask_fsp( - dirfsp, smb_fname->fsp, false, access_mask, &access_mask); + dirfsp, smb_fname->fsp, false, false, access_mask, &access_mask); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("smbd_calculate_access_mask_fsp " "on file %s returned %s\n", @@ -5031,7 +5047,7 @@ static NTSTATUS open_directory(connection_struct *conn, } status = smbd_calculate_access_mask_fsp( - dirfsp, smb_dname->fsp, false, access_mask, &access_mask); + dirfsp, smb_dname->fsp, false, false, access_mask, &access_mask); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("smbd_calculate_access_mask_fsp " "on file %s returned %s\n", diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 228433eb3e9..7f61514defc 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -1795,6 +1795,7 @@ static void smbd_smb2_create_after_exec(struct tevent_req *req) conn->cwd_fsp, state->result, false, + true, SEC_FLAG_MAXIMUM_ALLOWED, &max_access_granted);