****************************************************************************/
bool can_delete_file_in_directory(connection_struct *conn,
- const struct smb_filename *smb_fname)
+ const struct smb_filename *smb_fname)
{
TALLOC_CTX *ctx = talloc_tos();
- char *dname = NULL;
struct smb_filename *smb_fname_parent = NULL;
- NTSTATUS status;
bool ret;
if (!CAN_WRITE(conn)) {
}
/* Get the parent directory permission mask and owners. */
- if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) {
- return False;
- }
-
- status = create_synthetic_smb_fname(ctx, dname, NULL, NULL,
- &smb_fname_parent);
- if (!NT_STATUS_IS_OK(status)) {
- ret = false;
- goto out;
+ ret = parent_smb_fname(ctx, smb_fname, &smb_fname_parent, NULL);
+ if (ret != true) {
+ return false;
}
if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
ret = NT_STATUS_IS_OK(smbd_check_access_rights(conn,
smb_fname_parent,
+ false,
FILE_DELETE_CHILD));
out:
- TALLOC_FREE(dname);
TALLOC_FREE(smb_fname_parent);
return ret;
}
/****************************************************************************
Userspace check for write access.
- Note this doesn't take into account share write permissions.
****************************************************************************/
bool can_write_to_file(connection_struct *conn,
{
return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
smb_fname,
+ false,
FILE_WRITE_DATA));
}
Check for an existing default Windows ACL on a directory.
****************************************************************************/
-bool directory_has_default_acl(connection_struct *conn, const char *fname)
+bool directory_has_default_acl(connection_struct *conn,
+ struct files_struct *dirfsp,
+ struct smb_filename *smb_fname)
{
- /* returns talloced off tos. */
struct security_descriptor *secdesc = NULL;
unsigned int i;
- NTSTATUS status = SMB_VFS_GET_NT_ACL(conn, fname,
- SECINFO_DACL, &secdesc);
+ NTSTATUS status;
+
+ status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
+ SECINFO_DACL, talloc_tos(),
+ &secdesc);
- if (!NT_STATUS_IS_OK(status) || secdesc == NULL) {
+ if (!NT_STATUS_IS_OK(status) ||
+ secdesc == NULL ||
+ secdesc->dacl == NULL) {
+ TALLOC_FREE(secdesc);
return false;
}
TALLOC_FREE(secdesc);
return false;
}
+
+/****************************************************************************
+ Check if setting delete on close is allowed on this fsp.
+****************************************************************************/
+
+NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32_t dosmode)
+{
+ /*
+ * Only allow delete on close for writable files.
+ */
+
+ if ((dosmode & FILE_ATTRIBUTE_READONLY) &&
+ !lp_delete_readonly(SNUM(fsp->conn))) {
+ DEBUG(10,("can_set_delete_on_close: file %s delete on close "
+ "flag set but file attribute is readonly.\n",
+ fsp_str_dbg(fsp)));
+ return NT_STATUS_CANNOT_DELETE;
+ }
+
+ /*
+ * Only allow delete on close for writable shares.
+ */
+
+ if (!CAN_WRITE(fsp->conn)) {
+ DEBUG(10,("can_set_delete_on_close: file %s delete on "
+ "close flag set but write access denied on share.\n",
+ fsp_str_dbg(fsp)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * Only allow delete on close for files/directories opened with delete
+ * intent.
+ */
+
+ if (!(fsp->access_mask & DELETE_ACCESS)) {
+ DEBUG(10,("can_set_delete_on_close: file %s delete on "
+ "close flag set but delete access denied.\n",
+ fsp_str_dbg(fsp)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* Don't allow delete on close for non-empty directories. */
+ if (fsp->fsp_flags.is_directory) {
+ SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name));
+
+ /* Or the root of a share. */
+ if (ISDOT(fsp->fsp_name->base_name)) {
+ DEBUG(10,("can_set_delete_on_close: can't set delete on "
+ "close for the root of a share.\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return can_delete_directory_fsp(fsp);
+ }
+
+ return NT_STATUS_OK;
+}