s3: smbd: Reformat definition and callers of can_delete_file_in_directory().
[gd/samba-autobuild/.git] / source3 / smbd / file_access.c
index ae13a0a2a5d39b539475120be08ace66e6d599eb..6c4f38b6a9cf612d8b0913b7ade8b042221fbff0 100644 (file)
 ****************************************************************************/
 
 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)) {
@@ -51,15 +49,9 @@ bool can_delete_file_in_directory(connection_struct *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) {
@@ -124,16 +116,15 @@ bool can_delete_file_in_directory(connection_struct *conn,
 
        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,
@@ -141,6 +132,7 @@ bool can_write_to_file(connection_struct *conn,
 {
        return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
                                smb_fname,
+                               false,
                                FILE_WRITE_DATA));
 }
 
@@ -148,15 +140,22 @@ bool can_write_to_file(connection_struct *conn,
  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;
        }
 
@@ -171,3 +170,61 @@ bool directory_has_default_acl(connection_struct *conn, const char *fname)
        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;
+}