diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c index 1eec448..5bddbd5 100644 --- a/source3/modules/vfs_acl_common.c +++ b/source3/modules/vfs_acl_common.c @@ -760,6 +760,46 @@ static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle, return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr); } +static int rmdir_acl_common(struct vfs_handle_struct *handle, + const char *path) +{ + SMB_STRUCT_STAT sbuf; + struct file_id id; + files_struct *fsp = NULL; + int ret; + + ret = SMB_VFS_NEXT_RMDIR(handle, path); + if (!(ret == -1 && errno == EACCES)) { + return ret; + } + + /* Ensure we have this directory open with DELETE access. */ + ret = vfs_stat_smb_fname(handle->conn, path, &sbuf); + if (ret == -1) { + return ret; + } + + id = vfs_file_id_from_sbuf(handle->conn, &sbuf); + for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) { + if (fsp->access_mask & DELETE_ACCESS) { + /* We did open this for delete, + * force the delete as root. + */ + break; + } + } + + if (!fsp) { + errno = EACCES; + return -1; + } + + become_root(); + ret = SMB_VFS_NEXT_RMDIR(handle, path); + unbecome_root(); + return ret; +} + static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, @@ -857,3 +897,37 @@ static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle, /* NOTREACHED */ return status; } + +static int unlink_acl_common(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname) +{ + struct file_id id; + files_struct *fsp = NULL; + int ret; + + ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname); + if (!(ret == -1 && errno == EACCES)) { + return ret; + } + + /* Ensure we have this file open with DELETE access. */ + id = vfs_file_id_from_sbuf(handle->conn, &smb_fname->st); + for (fsp = file_find_di_first(id); fsp; file_find_di_next(fsp)) { + if (fsp->access_mask & DELETE_ACCESS) { + /* We did open this for delete, + * force the delete as root. + */ + break; + } + } + + if (!fsp) { + errno = EACCES; + return -1; + } + + become_root(); + ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname); + unbecome_root(); + return ret; +} diff --git a/source3/modules/vfs_acl_tdb.c b/source3/modules/vfs_acl_tdb.c index a1088ab..2afe69d 100644 --- a/source3/modules/vfs_acl_tdb.c +++ b/source3/modules/vfs_acl_tdb.c @@ -265,7 +265,7 @@ static int unlink_acl_tdb(vfs_handle_struct *handle, goto out; } - ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp); + ret = unlink_acl_common(handle, smb_fname_tmp); if (ret == -1) { goto out; @@ -413,6 +413,7 @@ static struct vfs_fn_pointers vfs_acl_tdb_fns = { .connect_fn = connect_acl_tdb, .opendir = opendir_acl_common, .mkdir = mkdir_acl_common, + .rmdir = rmdir_acl_common, .open = open_acl_common, .create_file = create_file_acl_common, .unlink = unlink_acl_tdb, diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index 625ef91..18f2d42 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -199,8 +199,10 @@ static struct vfs_fn_pointers vfs_acl_xattr_fns = { .connect_fn = connect_acl_xattr, .opendir = opendir_acl_common, .mkdir = mkdir_acl_common, + .rmdir = rmdir_acl_common, .open = open_acl_common, .create_file = create_file_acl_common, + .unlink = unlink_acl_common, .fget_nt_acl = fget_nt_acl_common, .get_nt_acl = get_nt_acl_common, .fset_nt_acl = fset_nt_acl_common,