s3: smbd: Add check_parent_access_fsp().
authorJeremy Allison <jra@samba.org>
Thu, 20 May 2021 22:17:09 +0000 (15:17 -0700)
committerRalph Boehme <slow@samba.org>
Wed, 9 Jun 2021 13:14:30 +0000 (13:14 +0000)
Next migrate check_parent_access() users over to it.

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/smbd/open.c
source3/smbd/proto.h

index a8d9269acb254c4f154d239d5416c2cb334e003f..a8c3ec39239baf0980ef5ebd6a1f85cf25da3718 100644 (file)
@@ -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.
index 6eb63159a3b6196d74cd5b507dd02986263691d8..3d1ba16467be7e04f2c261267d2191b184374f32 100644 (file)
@@ -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,