[PATCHES] SMB2 client quota support
Jeremy Allison
jra at samba.org
Mon Oct 3 22:07:56 UTC 2016
On Sun, Oct 02, 2016 at 08:14:27PM +0300, Uri Simchoni wrote:
> 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).
LGTM - thanks ! Pushed.
> 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.
> >
>
> 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