summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Disseldorp <ddiss@samba.org>2013-11-18 14:54:31 +0100
committerJeremy Allison <jra@samba.org>2013-11-22 08:56:45 -0800
commit4ffc85dfc561b077eb1e7afe3b3e7445ea741d2a (patch)
tree5ea3c9710c9ce14cb8f73b9837e842bd0161275d
parentd8d5d4c7428683da04fa4c8b344504e7044f9b1c (diff)
downloadsamba-4ffc85dfc561b077eb1e7afe3b3e7445ea741d2a.tar.gz
samba-4ffc85dfc561b077eb1e7afe3b3e7445ea741d2a.tar.xz
samba-4ffc85dfc561b077eb1e7afe3b3e7445ea741d2a.zip
smb2/ioctl: add support for FSCTL_[GET/SET]_COMPRESSION
In line with MS-FSCC 2.3.47, the FSCTL_SET_COMPRESSION ioctl allows remote SMB2 clients to enable and disable compression on a per-file or per-directory basis. Compression state can be retrieved using the FSCTL_GET_COMPRESSION request. Signed-off-by: David Disseldorp <ddiss@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
-rw-r--r--source3/smbd/smb2_ioctl_filesys.c117
1 files changed, 115 insertions, 2 deletions
diff --git a/source3/smbd/smb2_ioctl_filesys.c b/source3/smbd/smb2_ioctl_filesys.c
index bc2925beb9..92bf63a9e2 100644
--- a/source3/smbd/smb2_ioctl_filesys.c
+++ b/source3/smbd/smb2_ioctl_filesys.c
@@ -3,6 +3,7 @@
Core SMB2 server
Copyright (C) Stefan Metzmacher 2009
+ Copyright (C) David Disseldorp 2013
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,20 +23,132 @@
#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "../libcli/smb/smb_common.h"
+#include "../libcli/security/security.h"
#include "../lib/util/tevent_ntstatus.h"
#include "rpc_server/srv_pipe_hnd.h"
#include "include/ntioctl.h"
+#include "../librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
#include "smb2_ioctl_private.h"
+static NTSTATUS fsctl_get_cmprn(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ size_t in_max_output,
+ DATA_BLOB *out_output)
+{
+ struct compression_state cmpr_state;
+ enum ndr_err_code ndr_ret;
+ DATA_BLOB output;
+ NTSTATUS status;
+
+ if (fsp == NULL) {
+ return NT_STATUS_FILE_CLOSED;
+ }
+
+ /* Windows doesn't check for SEC_FILE_READ_ATTRIBUTE permission here */
+
+ if ((fsp->conn->fs_capabilities & FILE_FILE_COMPRESSION) == 0) {
+ DEBUG(4, ("FS does not advertise compression support\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ ZERO_STRUCT(cmpr_state);
+ status = SMB_VFS_GET_COMPRESSION(fsp->conn,
+ mem_ctx,
+ fsp,
+ NULL,
+ &cmpr_state.format);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ndr_ret = ndr_push_struct_blob(&output, mem_ctx,
+ &cmpr_state,
+ (ndr_push_flags_fn_t)ndr_push_compression_state);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (in_max_output < output.length) {
+ DEBUG(1, ("max output %u too small for compression state %ld\n",
+ (unsigned int)in_max_output, (long int)output.length));
+ return NT_STATUS_INVALID_USER_BUFFER;
+ }
+ *out_output = output;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS fsctl_set_cmprn(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ DATA_BLOB *in_input)
+{
+ struct compression_state cmpr_state;
+ enum ndr_err_code ndr_ret;
+ NTSTATUS status;
+
+ if (fsp == NULL) {
+ return NT_STATUS_FILE_CLOSED;
+ }
+
+ /* WRITE_DATA permission is required, WRITE_ATTRIBUTES is not */
+ status = check_access(fsp->conn, fsp, NULL,
+ FILE_WRITE_DATA);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if ((fsp->conn->fs_capabilities & FILE_FILE_COMPRESSION) == 0) {
+ DEBUG(4, ("FS does not advertise compression support\n"));
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ ndr_ret = ndr_pull_struct_blob(in_input, mem_ctx, &cmpr_state,
+ (ndr_pull_flags_fn_t)ndr_pull_compression_state);
+ if (ndr_ret != NDR_ERR_SUCCESS) {
+ DEBUG(0, ("failed to unmarshall set compression req\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = SMB_VFS_SET_COMPRESSION(fsp->conn,
+ mem_ctx,
+ fsp,
+ cmpr_state.format);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
struct tevent_req *smb2_ioctl_filesys(uint32_t ctl_code,
struct tevent_context *ev,
struct tevent_req *req,
struct smbd_smb2_ioctl_state *state)
{
+ NTSTATUS status;
+
switch (ctl_code) {
- /* no filesystem device type ioctls are supported yet */
+ case FSCTL_GET_COMPRESSION:
+ status = fsctl_get_cmprn(state, ev, state->fsp,
+ state->in_max_output,
+ &state->out_output);
+ if (!tevent_req_nterror(req, status)) {
+ tevent_req_done(req);
+ }
+ return tevent_req_post(req, ev);
+ break;
+ case FSCTL_SET_COMPRESSION:
+ status = fsctl_set_cmprn(state, ev, state->fsp,
+ &state->in_input);
+ if (!tevent_req_nterror(req, status)) {
+ tevent_req_done(req);
+ }
+ return tevent_req_post(req, ev);
+ break;
default: {
- NTSTATUS status;
uint8_t *out_data = NULL;
uint32_t out_data_len = 0;