access_mask);
}
-NTSTATUS check_parent_access(struct connection_struct *conn,
- struct files_struct *dirfsp,
- struct smb_filename *smb_fname,
- uint32_t access_mask)
-{
- NTSTATUS status;
- struct security_descriptor *parent_sd = NULL;
- uint32_t access_granted = 0;
- struct smb_filename *parent_dir = NULL;
- struct share_mode_lock *lck = NULL;
- struct file_id id = {0};
- uint32_t name_hash;
- bool delete_on_close_set;
- int ret;
- TALLOC_CTX *frame = talloc_stackframe();
-
- /*
- * NB. When dirfsp != conn->cwd_fsp, we must
- * change parent_dir to be "." for the name here.
- */
-
- SMB_ASSERT(dirfsp == conn->cwd_fsp);
-
- status = SMB_VFS_PARENT_PATHNAME(conn,
- frame,
- smb_fname,
- &parent_dir,
- NULL);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- if (get_current_uid(conn) == (uid_t)0) {
- /* I'm sorry sir, I didn't know you were root... */
- DEBUG(10,("check_parent_access: root override "
- "on %s. Granting 0x%x\n",
- smb_fname_str_dbg(smb_fname),
- (unsigned int)access_mask ));
- status = NT_STATUS_OK;
- goto out;
- }
-
- status = SMB_VFS_GET_NT_ACL_AT(conn,
- dirfsp,
- parent_dir,
- SECINFO_DACL,
- frame,
- &parent_sd);
-
- if (!NT_STATUS_IS_OK(status)) {
- DBG_INFO("SMB_VFS_GET_NT_ACL_AT failed for "
- "%s with error %s\n",
- smb_fname_str_dbg(parent_dir),
- 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(conn),
- false,
- (access_mask & ~FILE_READ_ATTRIBUTES),
- &access_granted);
- if(!NT_STATUS_IS_OK(status)) {
- DEBUG(5,("check_parent_access: access check "
- "on directory %s for "
- "path %s for mask 0x%x returned (0x%x) %s\n",
- smb_fname_str_dbg(parent_dir),
- smb_fname->base_name,
- 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(conn))) {
- status = NT_STATUS_OK;
- goto out;
- }
-
- /* Check if the directory has delete-on-close set */
- ret = SMB_VFS_STAT(conn, parent_dir);
- if (ret != 0) {
- status = map_nt_error_from_unix(errno);
- goto out;
- }
-
- id = SMB_VFS_FILE_ID_CREATE(conn, &parent_dir->st);
-
- status = file_name_hash(conn, parent_dir->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, 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;
-}
-
/*
* Given an fsp that represents a parent directory,
* check if the requested access can be granted.