[PATCHES] SMB2 client quota support
Uri Simchoni
uri at samba.org
Thu Sep 22 17:09:18 UTC 2016
Hi,
Strange things can happen in those jet-lagged nights.
The attached patch set fixes a few issues with current quota support
code and then adds support for using smbcquotas with SMB2 and later
protocols.
Unlike the server-side lack of support, I don't consider smb2 client
quota to be a bugfix, but rather a feature, because a user can use tool
A in SMB1 mode and tool B in SMB2 mode, whereas with the server, a mount
dictates the protocol version of all operations, so if suddenly quota
doesn't work that's a degradation.
I intend to follow up with fixes to the server as well, and some of the
work here lays the ground work for that, but the patch has grown quite a
bit so I decided to stop here and submit it.
I also upstreamed wireshark patches to dissect it all.
The first 5 patches are bugfixes and the rest is cleanup / adding the
smb2 stuff. It can be squashed quite a bit since it's all around the
same 3-4 files - I'm open to suggestions.
Review appreciated,
Uri.
-------------- next part --------------
From f638503164c99eef468e43688c2588121b5b6c11 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Fri, 16 Sep 2016 21:57:50 +0300
Subject: [PATCH 01/19] s3-cliquota: correctly handle no-more-entries
When listing quota records, a Windows server would
return STATUS_SUCCESS until no more entries are available,
where it would return STATUS_NO_MORE_ENTRIES.
The fix keeps old behavior of empty answer also signifying
end of record, to maintain compatibility with Samba servers.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12270
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 875c419..778fefc 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -242,13 +242,15 @@ NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
&rparam, 0, &rparam_count,
&rdata, 0, &rdata_count);
- if (!NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
nt_errstr(status)));
goto cleanup;
}
- if (rdata_count == 0) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) ||
+ rdata_count == 0) {
*pqt_list = NULL;
return NT_STATUS_OK;
}
@@ -304,13 +306,16 @@ NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
&rparam, 0, &rparam_count,
&rdata, 0, &rdata_count);
- if (!NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
nt_errstr(status)));
goto cleanup;
}
- if (rdata_count == 0) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) ||
+ rdata_count == 0) {
+ status = NT_STATUS_OK;
break;
}
--
2.5.5
From da7153e83f162b88c333e015cec5d62abcb3f0bb Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Fri, 16 Sep 2016 22:01:46 +0300
Subject: [PATCH 02/19] smbcquotas: fix error message listing quotas
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12270
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/utils/smbcquotas.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c
index e6f1dfb..cda5f92 100644
--- a/source3/utils/smbcquotas.c
+++ b/source3/utils/smbcquotas.c
@@ -408,9 +408,9 @@ static int do_quota(struct cli_state *cli,
status = cli_list_user_quota(
cli, quota_fnum, &qtl);
if (!NT_STATUS_IS_OK(status)) {
- d_printf("%s cli_set_user_quota %s\n",
- nt_errstr(status),
- username_str);
+ d_printf(
+ "%s cli_list_user_quota\n",
+ nt_errstr(status));
return -1;
}
dump_ntquota_list(&qtl,verbose,numeric,SidToString);
--
2.5.5
From 5cf9f097905db57079527cf4a6b64724c0a3dbe9 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Sun, 18 Sep 2016 11:09:54 +0300
Subject: [PATCH 03/19] ntquotas: support "freeing" an empty quota list
This avoids dereferencing a null pointer if there's
an attempt to free an empty list.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12270
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 3 ++-
source3/smbd/ntquotas.c | 3 +--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 778fefc..a2c6edd 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -34,8 +34,9 @@ NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
{
- if (!qt_list)
+ if (!qt_list || !*qt_list) {
return;
+ }
if ((*qt_list)->mem_ctx)
talloc_destroy((*qt_list)->mem_ctx);
diff --git a/source3/smbd/ntquotas.c b/source3/smbd/ntquotas.c
index 9b2e39a..93f4a2a 100644
--- a/source3/smbd/ntquotas.c
+++ b/source3/smbd/ntquotas.c
@@ -231,8 +231,7 @@ int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list)
static int quota_handle_destructor(SMB_NTQUOTA_HANDLE *handle)
{
- if (handle->quota_list)
- free_ntquota_list(&handle->quota_list);
+ free_ntquota_list(&handle->quota_list);
return 0;
}
--
2.5.5
From bc87d94ac9338e1808925c7883e59b3c3e5b9ecb Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Thu, 22 Sep 2016 16:06:12 +0300
Subject: [PATCH 04/19] cliquota: fix param count when setting fs quota
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12270
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index a2c6edd..ce48257 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -451,7 +451,7 @@ NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
NULL, -1, /* name, fid */
0, 0, /* function, flags */
setup, 1, 0, /* setup */
- param, 8, 0, /* param */
+ param, 4, 0, /* param */
data, 48, 0, /* data */
NULL, /* recv_flags2 */
NULL, 0, NULL, /* rsetup */
--
2.5.5
From d2aff728c7f2c6af680224d0ea8dc03e4547e967 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Sun, 18 Sep 2016 11:05:23 +0300
Subject: [PATCH 05/19] smbd: free talloc context if no quota records are
available
When generating a list of user quota records, free the memory
context that controls this list if the list is empty. Otherwise,
the context remains unreferenced and memory is leaked.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12289
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/smbd/ntquotas.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/source3/smbd/ntquotas.c b/source3/smbd/ntquotas.c
index 93f4a2a..4acfa50 100644
--- a/source3/smbd/ntquotas.c
+++ b/source3/smbd/ntquotas.c
@@ -226,6 +226,9 @@ int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list)
}
endpwent();
+ if (*qt_list == NULL) {
+ TALLOC_FREE(mem_ctx);
+ }
return 0;
}
--
2.5.5
From 052944e44c02646c7deffea0d80d504c179ace5d Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 20 Sep 2016 14:32:06 +0300
Subject: [PATCH 06/19] s3-libsmb: Support getting fs attributes via SMB2
Add a wrapper function arounf GET_INFO to obtain
file system attributes, and plumb it in.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 77 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 1 +
source3/libsmb/clifsinfo.c | 4 +++
3 files changed, 82 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index ac72090..a998d6f 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -1756,6 +1756,83 @@ NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
}
/***************************************************************
+ Wrapper that allows SMB2 to query file system attributes.
+ Synchronous only.
+***************************************************************/
+
+NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
+{
+ NTSTATUS status;
+ uint16_t fnum = 0xffff;
+ DATA_BLOB outbuf = data_blob_null;
+ struct smb2_hnd *ph = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ /* First open the top level directory. */
+ status =
+ cli_smb2_create_fnum(cli, "", 0, /* create_flags */
+ FILE_READ_ATTRIBUTES, /* desired_access */
+ FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
+ FILE_SHARE_READ | FILE_SHARE_WRITE |
+ FILE_SHARE_DELETE, /* share_access */
+ FILE_OPEN, /* create_disposition */
+ FILE_DIRECTORY_FILE, /* create_options */
+ &fnum,
+ NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = map_fnum_to_smb2_handle(cli, fnum, &ph);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
+ cli->smb2.tcon, 2, /* in_info_type */
+ 5, /* in_file_info_class */
+ 0xFFFF, /* in_max_output_length */
+ NULL, /* in_input_buffer */
+ 0, /* in_additional_info */
+ 0, /* in_flags */
+ ph->fid_persistent, ph->fid_volatile, frame,
+ &outbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ if (outbuf.length < 12) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto fail;
+ }
+
+ *fs_attr = IVAL(outbuf.data, 0);
+
+fail:
+
+ if (fnum != 0xffff) {
+ cli_smb2_close_fnum(cli, fnum);
+ }
+
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/***************************************************************
Wrapper that allows SMB2 to query a security descriptor.
Synchronous only.
***************************************************************/
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 0436c68..2df54a3 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -121,6 +121,7 @@ NTSTATUS cli_smb2_dskattr(struct cli_state *cli,
uint64_t *bsize,
uint64_t *total,
uint64_t *avail);
+NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr);
NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli,
uint16_t fnum,
uint32_t sec_info,
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
index ddc9efd..31a2c02 100644
--- a/source3/libsmb/clifsinfo.c
+++ b/source3/libsmb/clifsinfo.c
@@ -337,6 +337,10 @@ NTSTATUS cli_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_get_fs_attr_info(cli, fs_attr);
+ }
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
return NT_STATUS_INVALID_PARAMETER;
}
--
2.5.5
From 79bc9e193f306f46ad5d462c078c034aa2c74d92 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 12 Sep 2016 22:33:12 +0300
Subject: [PATCH 07/19] s3-libsmb: make parse_user_quota_record() public
For reuse by SMB2 client code.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 6 ++----
source3/libsmb/proto.h | 2 ++
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index ce48257..f3d93ae 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -46,10 +46,8 @@ void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
return;
}
-static bool parse_user_quota_record(const uint8_t *rdata,
- unsigned int rdata_count,
- unsigned int *offset,
- SMB_NTQUOTA_STRUCT *pqt)
+bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
+ unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt)
{
int sid_len;
SMB_NTQUOTA_STRUCT qt;
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index c0e1b74..879d713 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -762,6 +762,8 @@ int cli_printjob_del(struct cli_state *cli, int job);
NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum);
void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list);
+bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
+ unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
--
2.5.5
From 1d6a63751065cb98f4fa92378dfc42566f509940 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 12 Sep 2016 22:38:15 +0300
Subject: [PATCH 08/19] s3-libsmb: support getting user's quota in SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 81 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 2 ++
source3/libsmb/cliquota.c | 5 +++
3 files changed, 88 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index a998d6f..7122731 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -37,6 +37,7 @@
#include "libsmb/proto.h"
#include "lib/util/tevent_ntstatus.h"
#include "../libcli/security/security.h"
+#include "../librpc/gen_ndr/ndr_security.h"
#include "lib/util_ea.h"
#include "librpc/gen_ndr/ndr_ioctl.h"
#include "ntioctl.h"
@@ -2347,6 +2348,86 @@ NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
return status;
}
+/***************************************************************
+ Wrapper that allows SMB2 to get user quota.
+ Synchronous only.
+***************************************************************/
+
+NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_STRUCT *pqt)
+{
+ NTSTATUS status;
+ DATA_BLOB inbuf = data_blob_null;
+ DATA_BLOB outbuf = data_blob_null;
+ struct smb2_hnd *ph = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+ unsigned sid_len;
+ unsigned int offset;
+ uint8_t *buf;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ sid_len = ndr_size_dom_sid(&pqt->sid, 0);
+
+ inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
+ if (inbuf.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ buf = inbuf.data;
+
+ SCVAL(buf, 0, 1); /* ReturnSingle */
+ SCVAL(buf, 1, 0); /* RestartScan */
+ SSVAL(buf, 2, 0); /* Reserved */
+ SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
+ SIVAL(buf, 8, 0); /* StartSidLength */
+ SIVAL(buf, 12, 0); /* StartSidOffset */
+ SIVAL(buf, 16, 0); /* NextEntryOffset */
+ SIVAL(buf, 20, sid_len); /* SidLength */
+ sid_linearize(buf + 24, sid_len, &pqt->sid);
+
+ status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
+ cli->smb2.tcon, 4, /* in_info_type */
+ 0, /* in_file_info_class */
+ 0xFFFF, /* in_max_output_length */
+ &inbuf, /* in_input_buffer */
+ 0, /* in_additional_info */
+ 0, /* in_flags */
+ ph->fid_persistent, ph->fid_volatile, frame,
+ &outbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
+ pqt)) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
+ }
+
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
struct cli_smb2_read_state {
struct tevent_context *ev;
struct cli_state *cli;
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 2df54a3..c60316f 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -149,6 +149,8 @@ NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
const char *ea_name,
const char *ea_val,
size_t ea_len);
+NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_STRUCT *pqt);
struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index f3d93ae..c9a7f57 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -23,6 +23,7 @@
#include "fake_file.h"
#include "../libcli/security/security.h"
#include "trans2.h"
+#include "../libcli/smb/smbXcli_base.h"
NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
{
@@ -116,6 +117,10 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
smb_panic("cli_get_user_quota() called with NULL Pointer!");
}
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_get_user_quota(cli, quota_fnum, pqt);
+ }
+
SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
SSVAL(params, 0,quota_fnum);
--
2.5.5
From a71cee9ceada5f5ddebbe8eed1f45c31835e046e Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Sun, 18 Sep 2016 11:13:16 +0300
Subject: [PATCH 09/19] cliquota: refactor and cleanup listing of user quotas
Split cli_list_user_quota into an outer loop function and
an inner loop function.
This simplifies the code somewhat, paves the way for SMB2
support, and fixes a couple of memory leaks in error
conditions. No functional changes.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 135 +++++++++++++++++-----------------------------
1 file changed, 50 insertions(+), 85 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index c9a7f57..7771d3c 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -208,8 +208,10 @@ NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
return status;
}
-NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
- SMB_NTQUOTA_LIST **pqt_list)
+static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int quota_fnum,
+ SMB_NTQUOTA_LIST **pqt_list,
+ bool first)
{
uint16_t setup[1];
uint8_t params[16];
@@ -218,19 +220,16 @@ NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
unsigned int offset;
const uint8_t *curdata = NULL;
unsigned int curdata_count = 0;
- TALLOC_CTX *mem_ctx = NULL;
SMB_NTQUOTA_STRUCT qt;
SMB_NTQUOTA_LIST *tmp_list_ent;
NTSTATUS status;
-
- if (!cli||!pqt_list) {
- smb_panic("cli_list_user_quota() called with NULL Pointer!");
- }
+ uint16_t op = first ? TRANSACT_GET_USER_QUOTA_LIST_START
+ : TRANSACT_GET_USER_QUOTA_LIST_CONTINUE;
SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
SSVAL(params, 0,quota_fnum);
- SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_START);
+ SSVAL(params, 2, op);
SIVAL(params, 4,0x00000000);
SIVAL(params, 8,0x00000000);
SIVAL(params,12,0x00000000);
@@ -248,20 +247,14 @@ NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
- DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
- nt_errstr(status)));
goto cleanup;
}
- if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) ||
- rdata_count == 0) {
- *pqt_list = NULL;
- return NT_STATUS_OK;
- }
-
- if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
- DEBUG(0,("talloc_init() failed\n"));
- return NT_STATUS_NO_MEMORY;
+ /* compat. with smbd + safeguard against
+ * endless loop
+ */
+ if (rdata_count == 0) {
+ status = NT_STATUS_NO_MORE_ENTRIES;
}
offset = 1;
@@ -272,19 +265,18 @@ NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
if (!parse_user_quota_record((const uint8_t *)curdata, curdata_count,
&offset, &qt)) {
DEBUG(1,("Failed to parse the quota record\n"));
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
goto cleanup;
}
if ((tmp_list_ent=talloc_zero(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
- DEBUG(0,("TALLOC_ZERO() failed\n"));
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto cleanup;
}
if ((tmp_list_ent->quotas=talloc_zero(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
- DEBUG(0,("TALLOC_ZERO() failed\n"));
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto cleanup;
}
memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
@@ -293,70 +285,43 @@ NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
DLIST_ADD((*pqt_list),tmp_list_ent);
}
- SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_LIST_CONTINUE);
- while(1) {
-
- TALLOC_FREE(rparam);
- TALLOC_FREE(rdata);
-
- status = cli_trans(talloc_tos(), cli, SMBnttrans,
- NULL, -1, /* name, fid */
- NT_TRANSACT_GET_USER_QUOTA, 0,
- setup, 1, 0, /* setup */
- params, 16, 4, /* params */
- NULL, 0, 2048, /* data */
- NULL, /* recv_flags2 */
- NULL, 0, NULL, /* rsetup */
- &rparam, 0, &rparam_count,
- &rdata, 0, &rdata_count);
-
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
- DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n",
- nt_errstr(status)));
- goto cleanup;
- }
+cleanup:
+ TALLOC_FREE(rparam);
+ TALLOC_FREE(rdata);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) ||
- rdata_count == 0) {
- status = NT_STATUS_OK;
- break;
- }
+ return status;
+}
- offset = 1;
- for (curdata=rdata,curdata_count=rdata_count;
- ((curdata)&&(curdata_count>=8)&&(offset>0));
- curdata +=offset,curdata_count -= offset) {
- ZERO_STRUCT(qt);
- if (!parse_user_quota_record((const uint8_t *)curdata,
- curdata_count, &offset,
- &qt)) {
- DEBUG(1,("Failed to parse the quota record\n"));
- goto cleanup;
- }
-
- if ((tmp_list_ent=talloc_zero(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
- DEBUG(0,("TALLOC_ZERO() failed\n"));
- talloc_destroy(mem_ctx);
- goto cleanup;
- }
-
- if ((tmp_list_ent->quotas=talloc_zero(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
- DEBUG(0,("TALLOC_ZERO() failed\n"));
- talloc_destroy(mem_ctx);
- goto cleanup;
- }
-
- memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
- tmp_list_ent->mem_ctx = mem_ctx;
-
- DLIST_ADD((*pqt_list),tmp_list_ent);
- }
+NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_LIST **pqt_list)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ bool first = true;
+
+ if (!cli || !pqt_list) {
+ smb_panic("cli_list_user_quota() called with NULL Pointer!");
}
- cleanup:
- TALLOC_FREE(rparam);
- TALLOC_FREE(rdata);
+ *pqt_list = NULL;
+
+ if ((mem_ctx = talloc_init("SMB_USER_QUOTA_LIST")) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ do {
+ status = cli_list_user_quota_step(cli, mem_ctx, quota_fnum,
+ pqt_list, first);
+ first = false;
+ } while (NT_STATUS_IS_OK(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
+ status = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status) || *pqt_list == NULL) {
+ TALLOC_FREE(mem_ctx);
+ }
return status;
}
--
2.5.5
From 948c6d1c4c6f292e1be63b95296d7b6bd62840d9 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 19 Sep 2016 18:24:58 +0300
Subject: [PATCH 10/19] cliquota: some security hardening
Add some checks for validity of the offset in
the return buffer.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 7771d3c..74ca033 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -76,6 +76,10 @@ bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
return False;
}
+ if (*offset != 0 && *offset < 40 + sid_len) {
+ return false;
+ }
+
/* unknown 8 bytes in pdata
* maybe its the change time in NTTIME
*/
@@ -257,10 +261,9 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
status = NT_STATUS_NO_MORE_ENTRIES;
}
- offset = 1;
- for (curdata=rdata,curdata_count=rdata_count;
- ((curdata)&&(curdata_count>=8)&&(offset>0));
- curdata +=offset,curdata_count -= offset) {
+ curdata = rdata;
+ curdata_count = rdata_count;
+ while (true) {
ZERO_STRUCT(qt);
if (!parse_user_quota_record((const uint8_t *)curdata, curdata_count,
&offset, &qt)) {
@@ -283,6 +286,25 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
tmp_list_ent->mem_ctx = mem_ctx;
DLIST_ADD((*pqt_list),tmp_list_ent);
+
+ if (offset > curdata_count) {
+ DEBUG(1, ("out of bounds offset in quota record\n"));
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto cleanup;
+ }
+
+ if (curdata + offset < curdata) {
+ DEBUG(1, ("Pointer overflow in quota record\n"));
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto cleanup;
+ }
+
+ curdata += offset;
+ curdata_count -= offset;
+
+ if (offset == 0) {
+ break;
+ }
}
cleanup:
--
2.5.5
From ced7a984496034bce9345e51bc9d4b087f34e885 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 19 Sep 2016 21:14:01 +0300
Subject: [PATCH 11/19] cliquota: factor out parsing of a quota record buffer
In preparation for SMB2 support, take parsing of the return
buffer into a separate function.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 117 ++++++++++++++++++++++++----------------------
source3/libsmb/proto.h | 3 ++
2 files changed, 65 insertions(+), 55 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 74ca033..0123810 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -104,6 +104,63 @@ bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
return True;
}
+NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_count,
+ TALLOC_CTX *mem_ctx, SMB_NTQUOTA_LIST **pqt_list)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ unsigned offset;
+ SMB_NTQUOTA_STRUCT qt;
+ SMB_NTQUOTA_LIST *tmp_list_ent;
+
+ while (true) {
+ ZERO_STRUCT(qt);
+ if (!parse_user_quota_record(curdata, curdata_count, &offset,
+ &qt)) {
+ DEBUG(1, ("Failed to parse the quota record\n"));
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ break;
+ }
+
+ if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) ==
+ NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ break;
+ }
+
+ if ((tmp_list_ent->quotas =
+ talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ break;
+ }
+
+ memcpy(tmp_list_ent->quotas, &qt, sizeof(qt));
+ tmp_list_ent->mem_ctx = mem_ctx;
+
+ DLIST_ADD((*pqt_list), tmp_list_ent);
+
+ if (offset > curdata_count) {
+ DEBUG(1, ("out of bounds offset in quota record\n"));
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ break;
+ }
+
+ if (curdata + offset < curdata) {
+ DEBUG(1, ("Pointer overflow in quota record\n"));
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ break;
+ }
+
+ curdata += offset;
+ curdata_count -= offset;
+
+ if (offset == 0) {
+ break;
+ }
+ }
+
+ return status;
+}
+
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt)
{
@@ -221,11 +278,6 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
uint8_t params[16];
uint8_t *rparam=NULL, *rdata=NULL;
uint32_t rparam_count=0, rdata_count=0;
- unsigned int offset;
- const uint8_t *curdata = NULL;
- unsigned int curdata_count = 0;
- SMB_NTQUOTA_STRUCT qt;
- SMB_NTQUOTA_LIST *tmp_list_ent;
NTSTATUS status;
uint16_t op = first ? TRANSACT_GET_USER_QUOTA_LIST_START
: TRANSACT_GET_USER_QUOTA_LIST_CONTINUE;
@@ -249,64 +301,19 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
&rparam, 0, &rparam_count,
&rdata, 0, &rdata_count);
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
- goto cleanup;
- }
-
/* compat. with smbd + safeguard against
* endless loop
*/
- if (rdata_count == 0) {
+ if (NT_STATUS_IS_OK(status) && rdata_count == 0) {
status = NT_STATUS_NO_MORE_ENTRIES;
}
- curdata = rdata;
- curdata_count = rdata_count;
- while (true) {
- ZERO_STRUCT(qt);
- if (!parse_user_quota_record((const uint8_t *)curdata, curdata_count,
- &offset, &qt)) {
- DEBUG(1,("Failed to parse the quota record\n"));
- status = NT_STATUS_INVALID_NETWORK_RESPONSE;
- goto cleanup;
- }
-
- if ((tmp_list_ent=talloc_zero(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto cleanup;
- }
-
- if ((tmp_list_ent->quotas=talloc_zero(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto cleanup;
- }
-
- memcpy(tmp_list_ent->quotas,&qt,sizeof(qt));
- tmp_list_ent->mem_ctx = mem_ctx;
-
- DLIST_ADD((*pqt_list),tmp_list_ent);
-
- if (offset > curdata_count) {
- DEBUG(1, ("out of bounds offset in quota record\n"));
- status = NT_STATUS_INVALID_NETWORK_RESPONSE;
- goto cleanup;
- }
-
- if (curdata + offset < curdata) {
- DEBUG(1, ("Pointer overflow in quota record\n"));
- status = NT_STATUS_INVALID_NETWORK_RESPONSE;
- goto cleanup;
- }
-
- curdata += offset;
- curdata_count -= offset;
-
- if (offset == 0) {
- break;
- }
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
}
+ status = parse_user_quota_list(rdata, rdata_count, mem_ctx, pqt_list);
+
cleanup:
TALLOC_FREE(rparam);
TALLOC_FREE(rdata);
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 879d713..28afbc1 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -764,6 +764,9 @@ NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum);
void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list);
bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt);
+NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_size,
+ TALLOC_CTX *mem_ctx,
+ SMB_NTQUOTA_LIST **pqt_list);
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
--
2.5.5
From fa2d8ad75de7b12afc958fa3d638f32a8dbb7cf7 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Mon, 19 Sep 2016 22:17:10 +0300
Subject: [PATCH 12/19] cliquota: implement quota listing in SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 71 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 3 ++
source3/libsmb/cliquota.c | 5 +++
3 files changed, 79 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 7122731..c371439 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2428,6 +2428,77 @@ fail:
return status;
}
+/***************************************************************
+ Wrapper that allows SMB2 to list user quota.
+ Synchronous only.
+***************************************************************/
+
+NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int quota_fnum,
+ SMB_NTQUOTA_LIST **pqt_list, bool first)
+{
+ NTSTATUS status;
+ DATA_BLOB inbuf = data_blob_null;
+ DATA_BLOB outbuf = data_blob_null;
+ struct smb2_hnd *ph = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+ uint8_t *buf;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ inbuf = data_blob_talloc_zero(frame, 16);
+ if (inbuf.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+
+ buf = inbuf.data;
+
+ SCVAL(buf, 0, 0); /* ReturnSingle */
+ SCVAL(buf, 1, first ? 1 : 0); /* RestartScan */
+ SSVAL(buf, 2, 0); /* Reserved */
+ SIVAL(buf, 4, 0); /* SidListLength */
+ SIVAL(buf, 8, 0); /* StartSidLength */
+ SIVAL(buf, 12, 0); /* StartSidOffset */
+
+ status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
+ cli->smb2.tcon, 4, /* in_info_type */
+ 0, /* in_file_info_class */
+ 0xFFFF, /* in_max_output_length */
+ &inbuf, /* in_input_buffer */
+ 0, /* in_additional_info */
+ 0, /* in_flags */
+ ph->fid_persistent, ph->fid_volatile, frame,
+ &outbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
+ pqt_list);
+
+cleanup:
+ TALLOC_FREE(frame);
+ return status;
+}
+
struct cli_smb2_read_state {
struct tevent_context *ev;
struct cli_state *cli;
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index c60316f..b8fc790 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -151,6 +151,9 @@ NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
size_t ea_len);
NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
+NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, int quota_fnum,
+ SMB_NTQUOTA_LIST **pqt_list, bool first);
struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 0123810..f3db45b 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -282,6 +282,11 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli,
uint16_t op = first ? TRANSACT_GET_USER_QUOTA_LIST_START
: TRANSACT_GET_USER_QUOTA_LIST_CONTINUE;
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_list_user_quota_step(cli, mem_ctx, quota_fnum,
+ pqt_list, first);
+ }
+
SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA);
SSVAL(params, 0,quota_fnum);
--
2.5.5
From be9fd4151d7e01cc84408060dc2a93073eb50b6d Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 20 Sep 2016 06:45:03 +0300
Subject: [PATCH 13/19] cliquota: factor out fs quota parsing
This code will be reused by SMB2 code.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 50 +++++++++++++++++++++++++++++++----------------
source3/libsmb/proto.h | 2 ++
2 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index f3db45b..ada5816 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -161,6 +161,38 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_count,
return status;
}
+NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, unsigned int rdata_count,
+ SMB_NTQUOTA_STRUCT *pqt)
+{
+ SMB_NTQUOTA_STRUCT qt;
+
+ ZERO_STRUCT(qt);
+
+ if (rdata_count < 48) {
+ /* minimum length is not enforced by SMB2 client.
+ */
+ DEBUG(1, ("small returned fs quota buffer\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /* unknown_1 24 NULL bytes in pdata*/
+
+ /* the soft quotas 8 bytes (uint64_t)*/
+ qt.softlim = BVAL(rdata, 24);
+
+ /* the hard quotas 8 bytes (uint64_t)*/
+ qt.hardlim = BVAL(rdata, 32);
+
+ /* quota_flags 2 bytes **/
+ qt.qflags = SVAL(rdata, 40);
+
+ qt.qtype = SMB_USER_FS_QUOTA_TYPE;
+
+ *pqt = qt;
+
+ return NT_STATUS_OK;
+}
+
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt)
{
@@ -367,11 +399,8 @@ NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
uint8_t param[2];
uint8_t *rdata=NULL;
uint32_t rdata_count=0;
- SMB_NTQUOTA_STRUCT qt;
NTSTATUS status;
- ZERO_STRUCT(qt);
-
if (!cli||!pqt) {
smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
}
@@ -397,20 +426,7 @@ NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
return status;
}
- /* unknown_1 24 NULL bytes in pdata*/
-
- /* the soft quotas 8 bytes (uint64_t)*/
- qt.softlim = BVAL(rdata,24);
-
- /* the hard quotas 8 bytes (uint64_t)*/
- qt.hardlim = BVAL(rdata,32);
-
- /* quota_flags 2 bytes **/
- qt.qflags = SVAL(rdata,40);
-
- qt.qtype = SMB_USER_FS_QUOTA_TYPE;
-
- *pqt = qt;
+ status = parse_fs_quota_buffer(rdata, rdata_count, pqt);
TALLOC_FREE(rdata);
return status;
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 28afbc1..075df01 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -767,6 +767,8 @@ bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_size,
TALLOC_CTX *mem_ctx,
SMB_NTQUOTA_LIST **pqt_list);
+NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, unsigned int rdata_count,
+ SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
--
2.5.5
From ca42788b3c88dfbd21f888d533355fe06ff6804d Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 20 Sep 2016 06:46:28 +0300
Subject: [PATCH 14/19] cliquota: support getting fs quota by SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 52 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 2 ++
source3/libsmb/cliquota.c | 4 ++++
3 files changed, 58 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index c371439..e86d228 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2499,6 +2499,58 @@ cleanup:
return status;
}
+/***************************************************************
+ Wrapper that allows SMB2 to get file system quota.
+ Synchronous only.
+***************************************************************/
+
+NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_STRUCT *pqt)
+{
+ NTSTATUS status;
+ DATA_BLOB outbuf = data_blob_null;
+ struct smb2_hnd *ph = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ status = smb2cli_query_info(
+ cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
+ 2, /* in_info_type */
+ SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
+ 0xFFFF, /* in_max_output_length */
+ NULL, /* in_input_buffer */
+ 0, /* in_additional_info */
+ 0, /* in_flags */
+ ph->fid_persistent, ph->fid_volatile, frame, &outbuf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
+
+cleanup:
+ TALLOC_FREE(frame);
+ return status;
+}
+
struct cli_smb2_read_state {
struct tevent_context *ev;
struct cli_state *cli;
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index b8fc790..0dfa543 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -154,6 +154,8 @@ NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli, int quota_fnum,
NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
TALLOC_CTX *mem_ctx, int quota_fnum,
SMB_NTQUOTA_LIST **pqt_list, bool first);
+NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_STRUCT *pqt);
struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index ada5816..382bcbe 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -405,6 +405,10 @@ NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
smb_panic("cli_get_fs_quota_info() called with NULL Pointer!");
}
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_get_fs_quota_info(cli, quota_fnum, pqt);
+ }
+
SSVAL(setup + 0, 0, TRANSACT2_QFSINFO);
SSVAL(param,0,SMB_FS_QUOTA_INFORMATION);
--
2.5.5
From 99953c722d9089112af9a266e22e6b3615c9ea9d Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Wed, 21 Sep 2016 18:37:40 +0300
Subject: [PATCH 15/19] cliquota: factor out building of FILE_QUOTA_INFORMATION
Add a function to build a FILE_QUOTA_INFORMATION buffer
out of a quota list, and a function that adds a record
to a quota list.
Some parameters of the new functions are unused by
client code, but will be used by server code.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 177 ++++++++++++++++++++++++++++++++++++---------
source3/libsmb/proto.h | 7 +-
source3/utils/smbcquotas.c | 16 +++-
3 files changed, 163 insertions(+), 37 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 382bcbe..37c80ca 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -47,6 +47,28 @@ void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list)
return;
}
+bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx, SMB_NTQUOTA_STRUCT *pqt,
+ SMB_NTQUOTA_LIST **pqt_list)
+{
+ SMB_NTQUOTA_LIST *tmp_list_ent;
+
+ if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) == NULL) {
+ return false;
+ }
+
+ if ((tmp_list_ent->quotas = talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) ==
+ NULL) {
+ return false;
+ }
+
+ *tmp_list_ent->quotas = *pqt;
+ tmp_list_ent->mem_ctx = mem_ctx;
+
+ DLIST_ADD((*pqt_list), tmp_list_ent);
+
+ return true;
+}
+
bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt)
{
@@ -110,7 +132,6 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_count,
NTSTATUS status = NT_STATUS_OK;
unsigned offset;
SMB_NTQUOTA_STRUCT qt;
- SMB_NTQUOTA_LIST *tmp_list_ent;
while (true) {
ZERO_STRUCT(qt);
@@ -121,23 +142,6 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_count,
break;
}
- if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) ==
- NULL) {
- status = NT_STATUS_NO_MEMORY;
- break;
- }
-
- if ((tmp_list_ent->quotas =
- talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) == NULL) {
- status = NT_STATUS_NO_MEMORY;
- break;
- }
-
- memcpy(tmp_list_ent->quotas, &qt, sizeof(qt));
- tmp_list_ent->mem_ctx = mem_ctx;
-
- DLIST_ADD((*pqt_list), tmp_list_ent);
-
if (offset > curdata_count) {
DEBUG(1, ("out of bounds offset in quota record\n"));
status = NT_STATUS_INVALID_NETWORK_RESPONSE;
@@ -150,6 +154,11 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_count,
break;
}
+ if (!add_record_to_ntquota_list(mem_ctx, &qt, pqt_list)) {
+ status = NT_STATUS_NO_MEMORY;
+ break;
+ }
+
curdata += offset;
curdata_count -= offset;
@@ -193,6 +202,109 @@ NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, unsigned int rdata_count,
return NT_STATUS_OK;
}
+NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list, uint32_t maxlen,
+ TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf,
+ SMB_NTQUOTA_LIST **end_ptr)
+{
+ uint32_t qt_len = 0;
+ uint8_t *entry;
+ uint32_t entry_len;
+ int sid_len;
+ SMB_NTQUOTA_LIST *qtl;
+ DATA_BLOB qbuf = data_blob_null;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ if (qt_list == NULL) {
+ status = NT_STATUS_OK;
+ *outbuf = data_blob_null;
+ if (end_ptr) {
+ *end_ptr = NULL;
+ }
+ return NT_STATUS_OK;
+ }
+
+ for (qtl = qt_list; qtl != NULL; qtl = qtl->next, qt_len += entry_len) {
+
+ sid_len = ndr_size_dom_sid(&qtl->quotas->sid, 0);
+ entry_len = 40 + sid_len;
+ /* Fixme: do we have a standard "round-up" primitive? */
+ entry_len = ((entry_len + 7) / 8) * 8;
+ }
+
+ if (maxlen > 0 && qt_len > maxlen) {
+ qt_len = maxlen;
+ }
+
+ qbuf = data_blob_talloc_zero(mem_ctx, qt_len);
+ if (qbuf.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (qt_len = 0, entry = qbuf.data; qt_list != NULL;
+ qt_list = qt_list->next, qt_len += entry_len, entry += entry_len) {
+
+ sid_len = ndr_size_dom_sid(&qt_list->quotas->sid, 0);
+ entry_len = 40 + sid_len;
+ /* Fixme: do we have a standard "round-up" primitive? */
+ entry_len = ((entry_len + 7) / 8) * 8;
+
+ if (qt_len + entry_len > qbuf.length) {
+ /* check for not-enough room even for a single
+ * entry
+ */
+ if (qt_len == 0) {
+ status = NT_STATUS_BUFFER_TOO_SMALL;
+ goto fail;
+ }
+
+ break;
+ }
+
+ /* nextoffset entry 4 bytes */
+ SIVAL(entry, 0, entry_len);
+
+ /* then the len of the SID 4 bytes */
+ SIVAL(entry, 4, sid_len);
+
+ /* NTTIME of last record change */
+ SBIG_UINT(entry, 8, (uint64_t)0);
+
+ /* the used disk space 8 bytes uint64_t */
+ SBIG_UINT(entry, 16, qt_list->quotas->usedspace);
+
+ /* the soft quotas 8 bytes uint64_t */
+ SBIG_UINT(entry, 24, qt_list->quotas->softlim);
+
+ /* the hard quotas 8 bytes uint64_t */
+ SBIG_UINT(entry, 32, qt_list->quotas->hardlim);
+
+ /* and now the SID */
+ sid_linearize((uint8_t *)(entry + 40), sid_len,
+ &qt_list->quotas->sid);
+ }
+
+ /* overwrite the offset of the last entry */
+ SIVAL(entry - entry_len, 0, 0);
+
+ /*potentially shrink the buffer if max was given
+ * and we haven't quite reached the max
+ */
+ qbuf.length = qt_len;
+ *outbuf = qbuf;
+ qbuf = data_blob_null;
+ status = NT_STATUS_OK;
+
+ if (end_ptr) {
+ *end_ptr = qt_list;
+ }
+
+fail:
+ data_blob_free(&qbuf);
+
+ return status;
+}
+
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt)
{
@@ -255,39 +367,32 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
}
NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
- SMB_NTQUOTA_STRUCT *pqt)
+ SMB_NTQUOTA_LIST *qtl)
{
uint16_t setup[1];
uint8_t params[2];
- uint8_t data[112];
- unsigned int sid_len;
- NTSTATUS status;
+ DATA_BLOB data = data_blob_null;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- memset(data,'\0',112);
-
- if (!cli||!pqt) {
+ if (!cli || !qtl) {
smb_panic("cli_set_user_quota() called with NULL Pointer!");
}
+ status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
SSVAL(params,0,quota_fnum);
- sid_len = ndr_size_dom_sid(&pqt->sid, 0);
- SIVAL(data,0,0);
- SIVAL(data,4,sid_len);
- SBIG_UINT(data, 8,(uint64_t)0);
- SBIG_UINT(data,16,pqt->usedspace);
- SBIG_UINT(data,24,pqt->softlim);
- SBIG_UINT(data,32,pqt->hardlim);
- sid_linearize(data+40, sid_len, &pqt->sid);
-
status = cli_trans(talloc_tos(), cli, SMBnttrans,
NULL, -1, /* name, fid */
NT_TRANSACT_SET_USER_QUOTA, 0,
setup, 1, 0, /* setup */
params, 2, 0, /* params */
- data, 112, 0, /* data */
+ data.data, data.length, 0, /* data */
NULL, /* recv_flags2 */
NULL, 0, NULL, /* rsetup */
NULL, 0, NULL, /* rparams */
@@ -298,6 +403,8 @@ NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
nt_errstr(status)));
}
+cleanup:
+ data_blob_free(&data);
return status;
}
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index 075df01..a2b22a6 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -762,6 +762,8 @@ int cli_printjob_del(struct cli_state *cli, int job);
NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum);
void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list);
+bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx, SMB_NTQUOTA_STRUCT *pqt,
+ SMB_NTQUOTA_LIST **pqt_list);
bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count,
unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_size,
@@ -769,10 +771,13 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_size,
SMB_NTQUOTA_LIST **pqt_list);
NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, unsigned int rdata_count,
SMB_NTQUOTA_STRUCT *pqt);
+NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list, uint32_t maxlen,
+ TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf,
+ SMB_NTQUOTA_LIST **end_ptr);
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
- SMB_NTQUOTA_STRUCT *pqt);
+ SMB_NTQUOTA_LIST *qtl);
NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_LIST **pqt_list);
NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c
index cda5f92..c122457 100644
--- a/source3/utils/smbcquotas.c
+++ b/source3/utils/smbcquotas.c
@@ -339,6 +339,7 @@ static int do_quota(struct cli_state *cli,
uint32_t fs_attrs = 0;
uint16_t quota_fnum = 0;
SMB_NTQUOTA_LIST *qtl = NULL;
+ TALLOC_CTX *qtl_ctx = NULL;
SMB_NTQUOTA_STRUCT qt;
NTSTATUS status;
@@ -386,8 +387,21 @@ static int do_quota(struct cli_state *cli,
break;
case QUOTA_SETLIM:
pqt->sid = qt.sid;
+ if ((qtl_ctx = talloc_init(
+ "SMB_USER_QUOTA_SET")) ==
+ NULL) {
+ return -1;
+ }
+
+ if (!add_record_to_ntquota_list(
+ qtl_ctx, pqt, &qtl)) {
+ TALLOC_FREE(qtl_ctx);
+ return -1;
+ }
+
status = cli_set_user_quota(
- cli, quota_fnum, pqt);
+ cli, quota_fnum, qtl);
+ free_ntquota_list(&qtl);
if (!NT_STATUS_IS_OK(status)) {
d_printf("%s cli_set_user_quota %s\n",
nt_errstr(status),
--
2.5.5
From 425114ffe4c0e29637b084b7e6f6601fec67a4c7 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Wed, 21 Sep 2016 19:35:39 +0300
Subject: [PATCH 16/19] cliquota: support setting user quota via SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 48 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 2 ++
source3/libsmb/cliquota.c | 4 ++++
3 files changed, 54 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index e86d228..c14aeaf 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2551,6 +2551,54 @@ cleanup:
return status;
}
+/***************************************************************
+ Wrapper that allows SMB2 to set user quota.
+ Synchronous only.
+***************************************************************/
+
+NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_LIST *qtl)
+{
+ NTSTATUS status;
+ DATA_BLOB inbuf = data_blob_null;
+ struct smb2_hnd *ph = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ status = smb2cli_set_info(cli->conn, cli->timeout, cli->smb2.session,
+ cli->smb2.tcon, 4, /* in_info_type */
+ 0, /* in_file_info_class */
+ &inbuf, /* in_input_buffer */
+ 0, /* in_additional_info */
+ ph->fid_persistent, ph->fid_volatile);
+cleanup:
+ TALLOC_FREE(frame);
+
+ return status;
+}
+
struct cli_smb2_read_state {
struct tevent_context *ev;
struct cli_state *cli;
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 0dfa543..8db9b97 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -156,6 +156,8 @@ NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
SMB_NTQUOTA_LIST **pqt_list, bool first);
NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
+NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_LIST *qtl);
struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 37c80ca..cfdfc8d 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -378,6 +378,10 @@ NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
smb_panic("cli_set_user_quota() called with NULL Pointer!");
}
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_set_user_quota(cli, quota_fnum, qtl);
+ }
+
status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL);
if (!NT_STATUS_IS_OK(status)) {
goto cleanup;
--
2.5.5
From ee859153690e5a509e6f39028f15f27c9231fbe6 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Wed, 21 Sep 2016 23:58:33 +0300
Subject: [PATCH 17/19] cliquota: factor out building of
FILE_FS_CONTROL_INFORMATION
add a service routine that builds FILE_FS_CONTROL_INFORMATION
with default quota and flags. This will be reused by SMB2 and
by server code.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cliquota.c | 63 +++++++++++++++++++++++++++++++++--------------
source3/libsmb/proto.h | 3 +++
2 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index cfdfc8d..904e271 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -305,6 +305,44 @@ fail:
return status;
}
+NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx,
+ const SMB_NTQUOTA_STRUCT *pqt, DATA_BLOB *blob,
+ uint32_t maxlen)
+{
+ uint8_t *buf;
+
+ if (maxlen > 0 && maxlen < 48) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ *blob = data_blob_talloc_zero(mem_ctx, 48);
+
+ if (!blob->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ buf = blob->data;
+
+ /* Unknown1 24 NULL bytes*/
+ SBIG_UINT(buf, 0, (uint64_t)0);
+ SBIG_UINT(buf, 8, (uint64_t)0);
+ SBIG_UINT(buf, 16, (uint64_t)0);
+
+ /* Default Soft Quota 8 bytes */
+ SBIG_UINT(buf, 24, pqt->softlim);
+
+ /* Default Hard Quota 8 bytes */
+ SBIG_UINT(buf, 32, pqt->hardlim);
+
+ /* Quota flag 4 bytes */
+ SIVAL(buf, 40, pqt->qflags);
+
+ /* 4 padding bytes */
+ SIVAL(buf, 44, 0);
+
+ return NT_STATUS_OK;
+}
+
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt)
{
@@ -552,40 +590,29 @@ NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
{
uint16_t setup[1];
uint8_t param[4];
- uint8_t data[48];
- SMB_NTQUOTA_STRUCT qt;
+ DATA_BLOB data = data_blob_null;
NTSTATUS status;
- ZERO_STRUCT(qt);
- memset(data,'\0',48);
if (!cli||!pqt) {
smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
}
+ status = build_fs_quota_buffer(talloc_tos(), pqt, &data, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
SSVAL(setup + 0, 0,TRANSACT2_SETFSINFO);
SSVAL(param,0,quota_fnum);
SSVAL(param,2,SMB_FS_QUOTA_INFORMATION);
- /* Unknown1 24 NULL bytes*/
-
- /* Default Soft Quota 8 bytes */
- SBIG_UINT(data,24,pqt->softlim);
-
- /* Default Hard Quota 8 bytes */
- SBIG_UINT(data,32,pqt->hardlim);
-
- /* Quota flag 2 bytes */
- SSVAL(data,40,pqt->qflags);
-
- /* Unknown3 6 NULL bytes */
-
status = cli_trans(talloc_tos(), cli, SMBtrans2,
NULL, -1, /* name, fid */
0, 0, /* function, flags */
setup, 1, 0, /* setup */
param, 4, 0, /* param */
- data, 48, 0, /* data */
+ data.data, data.length, 0, /* data */
NULL, /* recv_flags2 */
NULL, 0, NULL, /* rsetup */
NULL, 0, NULL, /* rparam */
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index a2b22a6..08d3829 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -774,6 +774,9 @@ NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, unsigned int rdata_count,
NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list, uint32_t maxlen,
TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf,
SMB_NTQUOTA_LIST **end_ptr);
+NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx,
+ const SMB_NTQUOTA_STRUCT *pqt, DATA_BLOB *blob,
+ uint32_t maxlen);
NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum,
--
2.5.5
From bb9738b4b0d5e1a657e1cc64c7674196e7ffed23 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Thu, 22 Sep 2016 01:03:41 +0300
Subject: [PATCH 18/19] cliquota: support setting file system quota via SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 43 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 2 ++
source3/libsmb/cliquota.c | 4 ++++
3 files changed, 49 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index c14aeaf..d3e4ad2 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2599,6 +2599,49 @@ cleanup:
return status;
}
+NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_STRUCT *pqt)
+{
+ NTSTATUS status;
+ DATA_BLOB inbuf = data_blob_null;
+ struct smb2_hnd *ph = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ status = map_fnum_to_smb2_handle(cli, quota_fnum, &ph);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto cleanup;
+ }
+
+ status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2cli_set_info(
+ cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon,
+ 2, /* in_info_type */
+ SMB_FS_QUOTA_INFORMATION - 1000, /* in_file_info_class */
+ &inbuf, /* in_input_buffer */
+ 0, /* in_additional_info */
+ ph->fid_persistent, ph->fid_volatile);
+cleanup:
+ TALLOC_FREE(frame);
+ return status;
+}
+
struct cli_smb2_read_state {
struct tevent_context *ev;
struct cli_state *cli;
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 8db9b97..6421cad 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -158,6 +158,8 @@ NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_STRUCT *pqt);
NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli, int quota_fnum,
SMB_NTQUOTA_LIST *qtl);
+NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
+ SMB_NTQUOTA_STRUCT *pqt);
struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct cli_state *cli,
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 904e271..0510729 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -597,6 +597,10 @@ NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum,
smb_panic("cli_set_fs_quota_info() called with NULL Pointer!");
}
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_set_fs_quota_info(cli, quota_fnum, pqt);
+ }
+
status = build_fs_quota_buffer(talloc_tos(), pqt, &data, 0);
if (!NT_STATUS_IS_OK(status)) {
return status;
--
2.5.5
From e3aa6bdd89b0e5fdc5d57e39987bf2ee92a14332 Mon Sep 17 00:00:00 2001
From: Uri Simchoni <uri at samba.org>
Date: Tue, 20 Sep 2016 18:51:00 +0300
Subject: [PATCH 19/19] smbcquotas: add -m option
Add the "standard" -m command line option that controls max
client protocol.
Signed-off-by: Uri Simchoni <uri at samba.org>
---
docs-xml/manpages/smbcquotas.1.xml | 12 ++++++++++++
source3/utils/smbcquotas.c | 6 ++++++
2 files changed, 18 insertions(+)
diff --git a/docs-xml/manpages/smbcquotas.1.xml b/docs-xml/manpages/smbcquotas.1.xml
index bbdb9fd..bff24a4 100644
--- a/docs-xml/manpages/smbcquotas.1.xml
+++ b/docs-xml/manpages/smbcquotas.1.xml
@@ -34,6 +34,7 @@
<arg choice="opt">-V</arg>
<arg choice="opt">-U username</arg>
+ <arg choice="opt">-m|--max-protocol LEVEL</arg>
<arg choice="opt">-N</arg>
<arg choice="opt">-k</arg>
<arg choice="opt">-A</arg>
@@ -96,6 +97,17 @@
</varlistentry>
<varlistentry>
+ <term>-m|--max-protocol PROTOCOL_NAME</term>
+ <listitem><para>This allows the user to select the
+ highest SMB protocol level that smbcquotas will use to
+ connect to the server. By default this is set to
+ NT1, which is the highest available SMB1 protocol.
+ To connect using SMB2 or SMB3 protocol, use the
+ strings SMB2 or SMB3 respectively.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-t|--test-args</term>
<listitem><para>
Don't actually do anything, only validate the correctness of the arguments.
diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c
index c122457..06ecea1 100644
--- a/source3/utils/smbcquotas.c
+++ b/source3/utils/smbcquotas.c
@@ -598,6 +598,8 @@ FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" },
{ "numeric", 'n', POPT_ARG_NONE, NULL, 'n', "Don't resolve sids or limits to names" },
{ "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "be verbose" },
{ "test-args", 't', POPT_ARG_NONE, NULL, 't', "Test arguments"},
+ {"max-protocol", 'm', POPT_ARG_STRING, NULL, 'm',
+ "Set the max protocol level", "LEVEL"},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
{ NULL }
@@ -679,6 +681,10 @@ FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" },
}
todo = SET_QUOTA;
break;
+ case 'm':
+ lp_set_cmdline("client max protocol",
+ poptGetOptArg(pc));
+ break;
}
}
--
2.5.5
More information about the samba-technical
mailing list