[PATCHES] SMB2 client quota support
Uri Simchoni
uri at samba.org
Sun Oct 2 17:14:27 UTC 2016
Attached v2 of the patch.
In addition to addressing Jeremy's comments, it re-formats all new /
modified function declarations according to recommended style, and
assigns some patches to their individual bug (instead of piling
semi-related patches on the same bug).
Thanks,
Uri.
On 09/26/2016 11:05 PM, Jeremy Allison wrote:
> On Thu, Sep 22, 2016 at 08:09:18PM +0300, Uri Simchoni wrote:
>> Hi,
>>
>
> 1). Hate this reformatting... :-)
>
> [PATCH 07/19] s3-libsmb: make parse_user_quota_record() public
>
> -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)
>
Me too. Fixed. (I delegated formatting to a computer because overall it
does it much better than I do, so I accepted this reformatting, but
following your comment I fixed the clang-format file)
I re-formatted the whole patch set, so function declarations and
definitions are now following the preferred style.
>
> 2). In [PATCH 08/19] s3-libsmb: support getting user's quota in SMB2
>
> + SIVAL(buf, 4, 8 + sid_len); /* SidListLength */
>
> wrap check on 8 + sid_len please. I know it almost
> certainly can't wrap, but I want to beat into everyone's
> skulls when doing network marshalling in C *ALWAYS CHECK
> FOR INTEGER WRAP !!!*.
>
> I have a vain hope it'll prevent a security bug someday :-).
>
Done.
> 3). [PATCH 10/19] cliquota: some security hardening
>
> + if (*offset != 0 && *offset < 40 + sid_len) {
> + return false;
> + }
>
> wrap check on 40 + sid_len please !
>
Done.
> 4). [PATCH 15/19] cliquota: factor out building of FILE_QUOTA_INFORMATION
>
> + 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;
> + }
>
> wrap checks here please.
>
> + 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;
>
> and here.
>
Done.
> Otherwise looks good ! As a follow-up, in:
>
> [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.
>
> Should we fix smbd to do the same as Windows here ?
>
I believe we should, and plan to do it when I get to the server side.
However, quota listing in smbd is pretty much POC level right now IMHO.
The code loops over all users (using getpwent()) and checks their quota
- this won't work with AD member setups, and if it did, it wouldn't
scale. A proper implementation should delegate quota listing to VFS, as
a separate operation, with only the default doing what's done today.
> Jeremy.
>
-------------- next part --------------
From e01b64883285041978344bfbf06e68a8f348693f 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 v2 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 b2a8eee2833cfc1504dcb9bdf43ba175d012f31e 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 v2 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 68342a486d227c6c2ef700e80d1476ad86792db6 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 v2 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=12307
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 35f2b7ab8d3ace25e44aed64a417372fb66f32c7 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 v2 04/19] cliquota: fix param count when setting fs quota
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12288
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 14bbcd6039112e9c851431537fa3385ca33c0eee 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 v2 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 7c436fd7800534acc2a0bf2b08969fd0ab83fbc2 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 v2 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 73d207d81a5997133b8e6c6d3572855fe342c760 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 v2 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 | 8 ++++----
source3/libsmb/proto.h | 4 ++++
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index ce48257..3091efb 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -46,10 +46,10 @@ 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..ecfb0a3 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -762,6 +762,10 @@ 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 2ea18f0d4d7ff2415ec713eb6adeba9b62ec33cc 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 v2 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 | 86 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 3 ++
source3/libsmb/cliquota.c | 5 +++
3 files changed, 94 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index a998d6f..a841f4c 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,91 @@ 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 */
+ if (8 + sid_len < 8) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ 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..93d7529 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -149,6 +149,9 @@ 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 3091efb..1f89176 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)
{
@@ -118,6 +119,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 e1d34d5342c546eb1ba3c239bc104a6b65895c42 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 v2 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 | 137 ++++++++++++++++++----------------------------
1 file changed, 52 insertions(+), 85 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 1f89176..84028bb 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -210,8 +210,11 @@ 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];
@@ -220,19 +223,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);
@@ -250,20 +250,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;
@@ -274,19 +268,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));
@@ -295,70 +288,44 @@ 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 eb16533dedfdefceb6c1a4af948b4f701fa06a14 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 v2 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 | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 84028bb..e4589c4 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -73,11 +73,18 @@ bool parse_user_quota_record(const uint8_t *rdata,
/* sid len */
sid_len = IVAL(rdata,4);
+ if (40 + sid_len < 40) {
+ return false;
+ }
if (rdata_count < 40+sid_len) {
return False;
}
+ if (*offset != 0 && *offset < 40 + sid_len) {
+ return false;
+ }
+
/* unknown 8 bytes in pdata
* maybe its the change time in NTTIME
*/
@@ -260,10 +267,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)) {
@@ -286,6 +292,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 cc8698239cff20917ad4e6ef1f0a1b1c0195b048 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 v2 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 | 119 +++++++++++++++++++++++++---------------------
source3/libsmb/proto.h | 4 ++
2 files changed, 68 insertions(+), 55 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index e4589c4..19c2e7e 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -109,6 +109,65 @@ bool parse_user_quota_record(const uint8_t *rdata,
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)
{
@@ -227,11 +286,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;
@@ -255,64 +309,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 ecfb0a3..85cf44a 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -766,6 +766,10 @@ 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 c7879ed2183081c9a01973fba248ba3b4e48c5fc 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 v2 12/19] cliquota: implement quota listing in SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 73 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 5 +++
source3/libsmb/cliquota.c | 5 +++
3 files changed, 83 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index a841f4c..3f5629c 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2433,6 +2433,79 @@ 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 93d7529..b39bfed 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -152,6 +152,11 @@ NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
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 19c2e7e..ff7e6e6 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -290,6 +290,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 680ab0ed60422a270d7c65622224b560727937bf 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 v2 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 | 51 +++++++++++++++++++++++++++++++----------------
source3/libsmb/proto.h | 3 +++
2 files changed, 37 insertions(+), 17 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index ff7e6e6..cec378f 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -168,6 +168,39 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata,
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)
{
@@ -376,11 +409,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!");
}
@@ -406,20 +436,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 85cf44a..eaa9c8e 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -770,6 +770,9 @@ 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 bed45a2196f51c3ddea6bb9640b09b0c476f5c7c 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 v2 14/19] cliquota: support getting fs quota by SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 53 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 3 +++
source3/libsmb/cliquota.c | 4 ++++
3 files changed, 60 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 3f5629c..1be9381 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2506,6 +2506,59 @@ 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 b39bfed..7fd97ec 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -157,6 +157,9 @@ NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
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 cec378f..9a80eef 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -415,6 +415,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 acde5e793c186cd2634e497f25e442199a73b136 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 v2 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 | 190 ++++++++++++++++++++++++++++++++++++---------
source3/libsmb/proto.h | 13 +++-
source3/utils/smbcquotas.c | 16 +++-
3 files changed, 180 insertions(+), 39 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 9a80eef..f11d9a2 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -47,6 +47,29 @@ 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,
@@ -117,7 +140,6 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata,
NTSTATUS status = NT_STATUS_OK;
unsigned offset;
SMB_NTQUOTA_STRUCT qt;
- SMB_NTQUOTA_LIST *tmp_list_ent;
while (true) {
ZERO_STRUCT(qt);
@@ -128,23 +150,6 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata,
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;
@@ -157,6 +162,11 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata,
break;
}
+ if (!add_record_to_ntquota_list(mem_ctx, &qt, pqt_list)) {
+ status = NT_STATUS_NO_MEMORY;
+ break;
+ }
+
curdata += offset;
curdata_count -= offset;
@@ -201,6 +211,119 @@ NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata,
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) {
+
+ sid_len = ndr_size_dom_sid(&qtl->quotas->sid, 0);
+ if (47 + sid_len < 47) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ entry_len = 40 + sid_len;
+ entry_len = ((entry_len + 7) / 8) * 8;
+
+ if (qt_len + entry_len < qt_len) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ qt_len += entry_len;
+ }
+
+ 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;
+ 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)
{
@@ -262,40 +385,33 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum,
return status;
}
-NTSTATUS cli_set_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_LIST *qtl)
{
uint16_t setup[1];
uint8_t params[2];
- uint8_t data[112];
- unsigned int sid_len;
- NTSTATUS status;
-
- memset(data,'\0',112);
+ DATA_BLOB data = data_blob_null;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- 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 */
@@ -306,6 +422,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 eaa9c8e..1372dee 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -766,6 +766,9 @@ bool parse_user_quota_record(const uint8_t *rdata,
unsigned int rdata_count,
unsigned int *offset,
SMB_NTQUOTA_STRUCT *pqt);
+bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx,
+ SMB_NTQUOTA_STRUCT *pqt,
+ SMB_NTQUOTA_LIST **pqt_list);
NTSTATUS parse_user_quota_list(const uint8_t *curdata,
uint32_t curdata_size,
TALLOC_CTX *mem_ctx,
@@ -773,10 +776,16 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata,
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);
+NTSTATUS cli_set_user_quota(struct cli_state *cli,
+ int quota_fnum,
+ 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 d45336f88f851284d1132e90ede10c05df2f7462 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 v2 16/19] cliquota: support setting user quota via SMB2
Signed-off-by: Uri Simchoni <uri at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 49 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 3 +++
source3/libsmb/cliquota.c | 4 ++++
3 files changed, 56 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 1be9381..9ee4dae 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2559,6 +2559,55 @@ 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 7fd97ec..7c618d1 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -160,6 +160,9 @@ NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
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 f11d9a2..57bffe2 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -397,6 +397,10 @@ cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST *qtl)
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 715b1e68e1065ac0c550fd41cad7a78f1f509dbf 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 v2 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 | 64 ++++++++++++++++++++++++++++++++++-------------
source3/libsmb/proto.h | 4 +++
2 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 57bffe2..09c3d4d 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -324,6 +324,45 @@ 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)
{
@@ -573,40 +612,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 1372dee..6da95d3 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -781,6 +781,10 @@ NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list,
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,
--
2.5.5
From e27f1e910e57d876143f10a001b7f04c09ff74bb 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 v2 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 | 44 ++++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 3 +++
source3/libsmb/cliquota.c | 4 ++++
3 files changed, 51 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 9ee4dae..cf00f60 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2608,6 +2608,50 @@ 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 7c618d1..3289f7e 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -163,6 +163,9 @@ NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
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 09c3d4d..e22ccdd 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -619,6 +619,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 6282bfa7302aec6764d96303fb705cc37dc7600d 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 v2 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