From 133196790a6fee0aa522937773e31210202ac96b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 20 May 2021 15:17:09 -0700 Subject: [PATCH] s3: smbd: Add check_parent_access_fsp(). Next migrate check_parent_access() users over to it. Signed-off-by: Jeremy Allison Reviewed-by: Ralph Boehme --- source3/smbd/open.c | 105 +++++++++++++++++++++++++++++++++++++++++++ source3/smbd/proto.h | 2 + 2 files changed, 107 insertions(+) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index a8d9269acb2..a8c3ec39239 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -463,6 +463,111 @@ out: return status; } +/* + * Given an fsp that represents a parent directory, + * check if the requested access can be granted. + */ +NTSTATUS check_parent_access_fsp(struct files_struct *fsp, + uint32_t access_mask) +{ + NTSTATUS status; + struct security_descriptor *parent_sd = NULL; + uint32_t access_granted = 0; + struct share_mode_lock *lck = NULL; + uint32_t name_hash; + bool delete_on_close_set; + TALLOC_CTX *frame = talloc_stackframe(); + + if (get_current_uid(fsp->conn) == (uid_t)0) { + /* I'm sorry sir, I didn't know you were root... */ + DBG_DEBUG("root override on %s. Granting 0x%x\n", + fsp_str_dbg(fsp), + (unsigned int)access_mask); + status = NT_STATUS_OK; + goto out; + } + + status = SMB_VFS_FGET_NT_ACL(fsp, + SECINFO_DACL, + frame, + &parent_sd); + + if (!NT_STATUS_IS_OK(status)) { + DBG_INFO("SMB_VFS_FGET_NT_ACL failed for " + "%s with error %s\n", + fsp_str_dbg(fsp), + nt_errstr(status)); + goto out; + } + + /* + * If we can access the path to this file, by + * default we have FILE_READ_ATTRIBUTES from the + * containing directory. See the section: + * "Algorithm to Check Access to an Existing File" + * in MS-FSA.pdf. + * + * se_file_access_check() also takes care of + * owner WRITE_DAC and READ_CONTROL. + */ + status = se_file_access_check(parent_sd, + get_current_nttok(fsp->conn), + false, + (access_mask & ~FILE_READ_ATTRIBUTES), + &access_granted); + if(!NT_STATUS_IS_OK(status)) { + DBG_INFO("access check " + "on directory %s for mask 0x%x returned (0x%x) %s\n", + fsp_str_dbg(fsp), + access_mask, + access_granted, + nt_errstr(status)); + goto out; + } + + if (!(access_mask & (SEC_DIR_ADD_FILE | SEC_DIR_ADD_SUBDIR))) { + status = NT_STATUS_OK; + goto out; + } + if (!lp_check_parent_directory_delete_on_close(SNUM(fsp->conn))) { + status = NT_STATUS_OK; + goto out; + } + + /* Check if the directory has delete-on-close set */ + status = file_name_hash(fsp->conn, + fsp->fsp_name->base_name, + &name_hash); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + /* + * Don't take a lock here. We just need a snapshot + * of the current state of delete on close and this is + * called in a codepath where we may already have a lock + * (and we explicitly can't hold 2 locks at the same time + * as that may deadlock). + */ + lck = fetch_share_mode_unlocked(frame, fsp->file_id); + if (lck == NULL) { + status = NT_STATUS_OK; + goto out; + } + + delete_on_close_set = is_delete_on_close_set(lck, name_hash); + if (delete_on_close_set) { + status = NT_STATUS_DELETE_PENDING; + goto out; + } + + status = NT_STATUS_OK; + +out: + TALLOC_FREE(frame); + return status; +} + /**************************************************************************** Ensure when opening a base file for a stream open that we have permissions to do so given the access mask on the base file. diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 6eb63159a3b..3d1ba16467b 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -745,6 +745,8 @@ NTSTATUS check_parent_access(struct connection_struct *conn, struct files_struct *dirfsp, struct smb_filename *smb_fname, uint32_t access_mask); +NTSTATUS check_parent_access_fsp(struct files_struct *fsp, + uint32_t access_mask); NTSTATUS fd_openat(const struct files_struct *dirfsp, struct smb_filename *smb_fname, files_struct *fsp, -- 2.47.3