RFC smbd smb2 quota support (+ patches to get rid of manual marshall/unmarshall by ndr-ising the existing code)
Noel Power
nopower at suse.com
Wed Mar 15 19:15:41 UTC 2017
On 15/03/17 18:52, Noel Power wrote:
> On 13/03/17 22:08, Noel Power wrote:
>> Hi Jeremy
>> On 13/03/17 09:15, Noel Power wrote:
>>> Hi Jeremy
>>> On 10/03/17 16:50, Jeremy Allison wrote:
>> [...]
>>>>> I don't get it :-( afaics whatever numbers (fake or otherwise) you pump
>>>>> into sid_list_length, start_sid_length or start_sid_offset you are going
>>>>> to end up with an effective array len of 0 -> 4294967295, if it is too
>>>>> big the ndr code will detect that, if it is too small then we will find
>>>>> out about that later.
>>>> I'm sure you're right, and I'll believe you. I still
>>>> don't want to see *ANY* unchecked arithmetic in values
>>>> read from the wire.
>>> that's fine, now I get where you are coming from, I will post new
>>> patches as soon as I rework the series
>>>
>>> Noel
>> please see latest patches, hopefully they cover the issues above,
>> additionally I added 2 more patches, one to enable smb2 for the existing
>> quota check and the other the follow-up patch to combine
>> build_user_quota_buffer & fill_quota_buffer into a single common func.
> bah, I have to say please ignore these for a moment, I spotted 2
> problems (1 the patches all don't build individually anymore and a small
> bug for smbcquota -C) I will post new patches later
>
> Noel
hopefully better now, please see attached, basically a couple of hunks
needed to be moved from Patch 11 to ensure Patch 8 would build.
Additionally Patch 11 was missing a test to see if max_data was
specified before checking if its value was exceeded
thanks
Noel
-------------- next part --------------
From 108055830c2956cf03b75a6f9429219fe8329cf9 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 28 Feb 2017 15:04:16 +0000
Subject: [PATCH 01/11] s3/libsmb: Avoid potential smbpanic calling
parse_user_quota_list.
Calling parse_user_quota_list with a NULL buffer can cause a panic, while
this shouldn't happen, I managed to trigger this with an early implementation
of SMB2 quota support in smbd which didn't pass back NT_STATUS_NO_MORE_ENTRIES
when handling a SMB2_0_INFO_QUOTA GETINFO message.
OTHOH the Windows client handled the same situation gracefully.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/libsmb/cli_smb2_fnum.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 848e077..7977bea 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -2532,6 +2532,14 @@ NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
ph->fid_persistent, ph->fid_volatile, frame,
&outbuf);
+ /*
+ * safeguard against panic from calling parse_user_quota_list with
+ * NULL buffer
+ */
+ if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
+ status = NT_STATUS_NO_MORE_ENTRIES;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
goto cleanup;
}
--
2.10.2
From a6d4cb74dbead9849c017c9a0d49b4f1621a8512 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 28 Feb 2017 11:36:47 +0000
Subject: [PATCH 02/11] s3/smbd: Don't stat when doing a quota operation (as
it's a fake file)
calling SMB_VFS_STAT on the quota fake file fails and caused
FS_INFO/FileFsControlInfo request to error out early, in turn stopped a
Win8.1 client from proceeding with quota queries.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/smbd/trans2.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index f58aacf..6de7795 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -3435,7 +3435,8 @@ NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
ZERO_STRUCT(smb_fname);
smb_fname.base_name = discard_const_p(char, filename);
- if(SMB_VFS_STAT(conn, &smb_fname) != 0) {
+ if(info_level != SMB_FS_QUOTA_INFORMATION
+ && SMB_VFS_STAT(conn, &smb_fname) != 0) {
DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
return map_nt_error_from_unix(errno);
}
--
2.10.2
From efb2162cc1777da6da3d28ea0840b861f44b8847 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Thu, 2 Mar 2017 09:20:24 +0000
Subject: [PATCH 03/11] librpc/idl Add some query [getset]info quota related
structures
Signed-off-by: Noel Power <noel.power at suse.com>
---
librpc/idl/quota.idl | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
librpc/idl/wscript_build | 1 +
librpc/wscript_build | 5 +++++
3 files changed, 60 insertions(+)
create mode 100644 librpc/idl/quota.idl
diff --git a/librpc/idl/quota.idl b/librpc/idl/quota.idl
new file mode 100644
index 0000000..7c4d00a
--- /dev/null
+++ b/librpc/idl/quota.idl
@@ -0,0 +1,54 @@
+#include "idl_types.h"
+
+import "security.idl";
+
+[
+ pointer_default(unique)
+]
+
+interface file_quota {
+
+ /* MS-FSCC 2.4.33.1 */
+ typedef [public] struct {
+ uint32 next_entry_offset;
+ uint32 sid_length;
+ dom_sid sid;
+ } file_get_quota_info;
+
+ /* MS-FSCC 2.4.33 */
+ typedef [public] struct {
+ uint32 next_entry_offset;
+ uint32 sid_length;
+ hyper change_time;
+ hyper quota_used;
+ hyper quota_threshold;
+ hyper quota_limit;
+ dom_sid sid;
+ } file_quota_information;
+}
+
+interface smb2_query_quoata
+{
+ /* MS-SMB2 2.2.37.1 */
+ typedef [public] struct {
+ uint8 return_single;
+ uint8 restart_scan;
+ uint16 reserved;
+ uint32 sid_list_length;
+ uint32 start_sid_length;
+ uint32 start_sid_offset;
+ } smb2_query_quota_info;
+}
+
+interface smb1_nt_transact_query_quota
+{
+ /* MS-SMB 2.2.7.5.1 */
+ typedef [public] struct {
+ uint16 fid;
+ uint8 return_single_entry;
+ uint8 restart_scan;
+ uint32 sid_list_length;
+ uint32 start_sid_length;
+ uint32 start_sid_offset;
+ } nttrans_query_quota_params;
+}
diff --git a/librpc/idl/wscript_build b/librpc/idl/wscript_build
index 1f09ae0..346ae78 100644
--- a/librpc/idl/wscript_build
+++ b/librpc/idl/wscript_build
@@ -12,6 +12,7 @@ bld.SAMBA_PIDL_LIST('PIDL',
drsblobs.idl efs.idl frstrans.idl mgmt.idl netlogon.idl
notify.idl
smb2_lease_struct.idl
+ quota.idl
policyagent.idl scerpc.idl svcctl.idl wkssvc.idl eventlog6.idl backupkey.idl
fsrvp.idl bkupblobs.idl fscc.idl frsblobs.idl witness.idl clusapi.idl
mdssvc.idl winspool.idl''',
diff --git a/librpc/wscript_build b/librpc/wscript_build
index fdfe641..e4af66c 100644
--- a/librpc/wscript_build
+++ b/librpc/wscript_build
@@ -399,6 +399,11 @@ bld.SAMBA_SUBSYSTEM('NDR_SMB2_LEASE_STRUCT',
public_headers='gen_ndr/smb2_lease_struct.h'
)
+bld.SAMBA_SUBSYSTEM('NDR_QUOTA',
+ source='gen_ndr/ndr_quota.c',
+ public_deps='ndr',
+ )
+
bld.SAMBA_SUBSYSTEM('NDR_SCHANNEL',
source='ndr/ndr_schannel.c gen_ndr/ndr_schannel.c',
public_deps='ndr ndr_nbt'
--
2.10.2
From b9cdf192d6c5f87f34bbd1ae123d72953eb2f748 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Tue, 21 Feb 2017 11:09:08 +0000
Subject: [PATCH 04/11] s3/smbd: Add support for GetInfo/SMB2_0_INFO_QUOTA
[MS-SMB2] 2.2.37.1 requests
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/smbd/nttrans.c | 369 ++++++++++++++++++++++++++++++++++++++++++++
source3/smbd/proto.h | 12 ++
source3/smbd/smb2_getinfo.c | 66 +++++++-
source3/wscript_build | 1 +
4 files changed, 445 insertions(+), 3 deletions(-)
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 5f122a9..ee9876e 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -30,6 +30,8 @@
#include "smbprofile.h"
#include "libsmb/libsmb.h"
#include "lib/util_ea.h"
+#include "librpc/gen_ndr/ndr_quota.h"
+#include "librpc/gen_ndr/ndr_security.h"
extern const struct generic_mapping file_generic_mapping;
@@ -2291,6 +2293,373 @@ static void call_nt_transact_ioctl(connection_struct *conn,
#ifdef HAVE_SYS_QUOTAS
+static enum ndr_err_code fill_qtlist_from_sids(TALLOC_CTX *mem_ctx,
+ struct files_struct *fsp,
+ SMB_NTQUOTA_HANDLE *qt_handle,
+ struct dom_sid *sids,
+ uint32_t elems)
+{
+ int i;
+ TALLOC_CTX *list_ctx = NULL;
+
+ list_ctx = talloc_init("quota_sid_list");
+
+ if (list_ctx == NULL) {
+ DBG_ERR("failed to allocate\n");
+ return NDR_ERR_ALLOC;
+ }
+
+ if (qt_handle->quota_list!=NULL) {
+ free_ntquota_list(&(qt_handle->quota_list));
+ }
+ for (i = 0; i < elems; i++) {
+ SMB_NTQUOTA_STRUCT qt;
+ SMB_NTQUOTA_LIST *list_item;
+
+ if (!NT_STATUS_IS_OK(vfs_get_ntquota(fsp,
+ SMB_USER_QUOTA_TYPE,
+ &sids[i], &qt))) {
+ /* non fatal error, return empty item in result */
+ ZERO_STRUCT(qt);
+ continue;
+ }
+
+
+ list_item = talloc_zero(list_ctx, SMB_NTQUOTA_LIST);
+ if (list_item == NULL) {
+ DBG_ERR("failed to allocate\n");
+ return NDR_ERR_ALLOC;
+ }
+
+ sid_to_uid(&sids[i], &list_item->uid);
+ list_item->quotas = talloc_zero(list_item, SMB_NTQUOTA_STRUCT);
+ if (list_item->quotas == NULL) {
+ DBG_ERR("failed to allocate\n");
+ return NDR_ERR_ALLOC;
+ }
+
+ *list_item->quotas = qt;
+ list_item->mem_ctx = list_ctx;
+ DLIST_ADD(qt_handle->quota_list, list_item);
+ }
+ qt_handle->tmp_list = qt_handle->quota_list;
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code extract_sids_from_buf(TALLOC_CTX *mem_ctx,
+ uint32_t sidlistlength,
+ uint32_t startsidlength,
+ uint32_t startsidoffset,
+ DATA_BLOB *sid_buf,
+ struct dom_sid **sids,
+ uint32_t *num)
+{
+ DATA_BLOB blob;
+ uint32_t i = 0;
+ enum ndr_err_code err;
+
+ struct sid_list_elem {
+ struct sid_list_elem *prev, *next;
+ struct dom_sid sid;
+ };
+
+ struct sid_list_elem *sid_list = NULL;
+ struct sid_list_elem *iter = NULL;
+ TALLOC_CTX *list_ctx = talloc_init("sid_list");
+ if (!list_ctx) {
+ DBG_ERR("OOM\n");
+ err = NDR_ERR_ALLOC;
+ goto done;
+ }
+
+ *num = 0;
+ *sids = NULL;
+
+ if (sidlistlength) {
+ uint32_t offset = 0;
+ bool can_pull = true;
+ struct ndr_pull *ndr_pull = NULL;
+
+ blob.data = sid_buf->data;
+ blob.length = sidlistlength;
+ ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
+ while (can_pull) {
+ struct file_get_quota_info info;
+ struct sid_list_elem *item = NULL;
+ uint32_t new_offset = 0;
+ NDR_PULL_NEED_BYTES(ndr_pull, offset);
+ err = ndr_pull_file_get_quota_info(ndr_pull,
+ NDR_SCALARS | NDR_BUFFERS, &info);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DBG_ERR("Failed to pull file_get_quota_info "
+ "from sidlist buffer\n");
+ goto done;
+ }
+ item = talloc_zero(list_ctx, struct sid_list_elem);
+ if (!item) {
+ DBG_ERR("OOM\n");
+ err = NDR_ERR_ALLOC;
+ goto done;
+ }
+ item->sid = info.sid;
+ DLIST_ADD(sid_list, item);
+ i++;
+ if (i == UINT32_MAX) {
+ DBG_ERR("Integer overflow\n");
+ err = NDR_ERR_ARRAY_SIZE;
+ goto done;
+ }
+ new_offset = info.next_entry_offset;
+ if (new_offset && new_offset <= offset) {
+ DBG_ERR("bad offset (old=0x%x, new=0x%x)\n",
+ offset,
+ new_offset);
+ err = NDR_ERR_OFFSET;
+ goto done;
+ }
+ offset = new_offset;
+ can_pull = (offset > 0);
+ }
+ *sids = talloc_zero_array(mem_ctx, struct dom_sid, i);
+ if (!sids) {
+ DBG_ERR("OOM\n");
+ err = NDR_ERR_ALLOC;
+ goto done;
+ }
+
+ *num = i;
+
+ for (iter = sid_list, i = 0; iter; iter = iter->next, i++) {
+ *sids[i] = iter->sid;
+ DBG_DEBUG("quota SID[%d] %s\n", i, sid_string_dbg(&iter->sid));
+ }
+ } else {
+ *sids = talloc_zero_array(mem_ctx, struct dom_sid, 1);
+ if (!sids) {
+ DBG_ERR("OOM\n");
+ err = NDR_ERR_ALLOC;
+ goto done;
+ }
+ err = ndr_pull_struct_blob(&blob, mem_ctx, &sids[0],
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DBG_ERR("Failed to pull sid from sid buffer\n");
+ goto done;
+ }
+ }
+
+ err = NDR_ERR_SUCCESS;
+done:
+ TALLOC_FREE(list_ctx);
+ return err;
+}
+
+static NTSTATUS fill_quota_buffer(TALLOC_CTX *mem_ctx,
+ SMB_NTQUOTA_HANDLE *qt_handle,
+ bool rescan,
+ bool return_single,
+ uint32_t max_data,
+ uint8_t **data,
+ uint32_t *datalen)
+{
+ SMB_NTQUOTA_STRUCT qt;
+ SMB_NTQUOTA_LIST *tmp_list;
+ int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+ struct ndr_push *header_ndr = ndr_push_init_ctx(mem_ctx);
+ uint32_t start_offset = 0;
+ uint32_t num_pushed = 0;
+ uint32_t next_align = 0;
+ bool max_data_exceeded = false;
+
+ ZERO_STRUCT(qt);
+ *data = NULL;
+ *datalen = 0;
+
+ if (rescan) {
+ tmp_list = qt_handle->quota_list;
+ } else {
+ tmp_list = qt_handle->tmp_list;
+ }
+
+ if (tmp_list == NULL) {
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+ for (;tmp_list!=NULL; tmp_list=tmp_list->next, num_pushed++) {
+ struct file_quota_information info;
+ enum ndr_err_code err;
+ ZERO_STRUCT(info);
+ info.sid_length = ndr_size_dom_sid(&tmp_list->quotas->sid, 0);
+
+ if (((header_ndr->offset - next_align)
+ + sizeof(info.next_entry_offset)
+ + sizeof(info.sid_length)
+ + sizeof(info.change_time)
+ + sizeof(info.quota_used)
+ + sizeof(info.quota_threshold)
+ + sizeof(info.quota_limit)
+ + info.sid_length) > max_data) {
+ max_data_exceeded = true;
+ break;
+ }
+ start_offset = header_ndr->offset;
+
+ info.sid = tmp_list->quotas->sid;
+ info.quota_used = tmp_list->quotas->usedspace;
+ info.quota_threshold = tmp_list->quotas->softlim;
+ info.quota_limit = tmp_list->quotas->hardlim;
+
+ err = ndr_push_file_quota_information(header_ndr,
+ ndr_flags,
+ &info);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DBG_DEBUG("Failed to pull the quota sid\n");
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* pidl will align to 8 bytes due to 8 byte members*/
+ next_align = header_ndr->offset;
+ ndr_push_align(header_ndr, 8);
+ next_align = header_ndr->offset - next_align;
+ info.next_entry_offset = header_ndr->offset - start_offset;
+
+ if (return_single) {
+ break;
+ }
+
+ /* write nextentryoffset to the buffer too */
+ SIVAL(header_ndr->data, start_offset, info.next_entry_offset);
+ }
+
+
+ qt_handle->tmp_list = tmp_list;
+
+ *datalen = header_ndr->offset - next_align;
+ *data = header_ndr->data;
+
+ if (num_pushed) {
+ /* terminate the list */
+ SIVAL(header_ndr->data, start_offset, 0);
+ }
+
+ /*
+ * if we failed to write a single file_quota_information
+ * issue BUFFER_TOO_SMALL
+ */
+ if (max_data_exceeded && num_pushed < 1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
+ files_struct *fsp,
+ struct smb2_query_quota_info *info,
+ DATA_BLOB *sid_buf,
+ uint32_t max_data_count,
+ uint8_t **p_data,
+ uint32_t *p_data_size)
+{
+ NTSTATUS status;
+ SMB_NTQUOTA_HANDLE *qt_handle = NULL;
+ uint8_t *data = NULL;
+ uint32_t data_size = 0;
+ enum ndr_err_code err;
+
+ DBG_DEBUG("sidlistlength = %d, startsidlength = %d, "
+ "startsidoffset = %d\n",
+ info->sid_list_length,
+ info->start_sid_length,
+ info->start_sid_offset);
+
+ qt_handle =
+ (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data;
+
+ if (info->sid_list_length || info->start_sid_length
+ || info->start_sid_offset) {
+ struct dom_sid *sids;
+ uint32_t elems = 0;
+ /*
+ * error check pulled offsets and lengths for wrap and
+ * exceeding available bytes.
+ */
+ if (info->sid_list_length) {
+ if (info->sid_list_length > sid_buf->length) {
+ DBG_ERR("sid_list_length 0x%x exceeds "
+ "available bytes %zx\n",
+ info->sid_list_length,
+ sid_buf->length);
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ } else {
+ if (!sid_buf->length) {
+ DBG_ERR("expected sid length but got none.\n");
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ if (info->start_sid_length + info->start_sid_offset
+ < info->start_sid_length) {
+ DBG_ERR("integer wrap detected\n");
+ err = NDR_ERR_ARRAY_SIZE;
+ goto done;
+ }
+ if (info->start_sid_length + info->start_sid_offset
+ > sid_buf->length) {
+ DBG_ERR("sidlistlength 0x%x + offset 0x%x "
+ "exceeds remaining bytes "
+ "in buffer %zx\n",
+ info->start_sid_length,
+ info->start_sid_offset,
+ sid_buf->length);
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ }
+
+ err = extract_sids_from_buf(mem_ctx, info->sid_list_length,
+ info->start_sid_length,
+ info->start_sid_offset,
+ sid_buf, &sids, &elems);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err) || elems == 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ err = fill_qtlist_from_sids(mem_ctx,
+ fsp,
+ qt_handle,
+ sids,
+ elems);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ } else if (info->restart_scan) {
+ if (vfs_get_user_ntquota_list(fsp,
+ &(qt_handle->quota_list))!=0) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+ } else {
+ if (qt_handle->quota_list!=NULL &&
+ qt_handle->tmp_list==NULL) {
+ free_ntquota_list(&(qt_handle->quota_list));
+ }
+ }
+
+ status = fill_quota_buffer(mem_ctx, qt_handle,
+ info->restart_scan !=0,
+ info->return_single != 0,
+ max_data_count,
+ &data,
+ &data_size);
+ *p_data = data;
+ *p_data_size = data_size;
+done:
+ return status;
+}
+
/****************************************************************************
Reply to get user quota
****************************************************************************/
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 7ccb12a..b74a183 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -633,6 +633,18 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
uint32_t max_data_count,
uint8_t **ppmarshalled_sd,
size_t *psd_size);
+#ifdef HAVE_SYS_QUOTAS
+
+struct smb2_query_quota_info;
+
+NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
+ files_struct *fsp,
+ struct smb2_query_quota_info *info,
+ DATA_BLOB *sidbuffer,
+ uint32_t max_data_count,
+ uint8_t **p_data,
+ uint32_t *p_data_size);
+#endif
void reply_nttrans(struct smb_request *req);
void reply_nttranss(struct smb_request *req);
diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c
index 7f44868..d56b63c 100644
--- a/source3/smbd/smb2_getinfo.c
+++ b/source3/smbd/smb2_getinfo.c
@@ -25,6 +25,8 @@
#include "../libcli/smb/smb_common.h"
#include "trans2.h"
#include "../lib/util/tevent_ntstatus.h"
+#include "librpc/gen_ndr/ndr_quota.h"
+#include "librpc/gen_ndr/ndr_security.h"
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -517,9 +519,67 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
break;
}
- case SMB2_GETINFO_QUOTA:
- tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
- return tevent_req_post(req, ev);
+ case SMB2_GETINFO_QUOTA: {
+ struct smb2_query_quota_info info;
+ enum ndr_err_code err;
+ uint8_t *data = NULL;
+ uint32_t data_size = 0;
+ struct ndr_pull *ndr_pull = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_init("geninfo_quota");
+ DATA_BLOB sid_buf = data_blob_null;
+ if (!tmp_ctx) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
+ }
+
+ ndr_pull = ndr_pull_init_blob(&in_input_buffer, tmp_ctx);
+ if (!ndr_pull) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
+ }
+
+ err = ndr_pull_smb2_query_quota_info(ndr_pull,
+ NDR_SCALARS | NDR_BUFFERS,
+ &info);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DBG_DEBUG("failed to pull smb2_query_quota_info\n");
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
+ DBG_DEBUG("quota list returnsingle %d, restartscan %d, "
+ "sid_list_length %d, start_sid_length %d, "
+ "startsidoffset %d\n",
+ info.return_single,
+ info.restart_scan,
+ info.sid_list_length,
+ info.start_sid_length,
+ info.start_sid_offset);
+
+ sid_buf.data = in_input_buffer.data + ndr_pull->offset;
+ sid_buf.length = in_input_buffer.length - ndr_pull->offset;
+
+ status = smbd_do_query_getinfo_quota(tmp_ctx,
+ fsp,
+ &info,
+ &sid_buf,
+ in_output_buffer_length,
+ &data,
+ &data_size);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(tmp_ctx);
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ state->out_output_buffer =
+ data_blob_talloc(state, data, data_size);
+ status = NT_STATUS_OK;
+ TALLOC_FREE(tmp_ctx);
+ break;
+ }
default:
DEBUG(10,("smbd_smb2_getinfo_send: "
diff --git a/source3/wscript_build b/source3/wscript_build
index 8c9a15b..3414761 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -753,6 +753,7 @@ bld.SAMBA3_LIBRARY('smbd_base',
netapi
NDR_IOCTL
notifyd
+ NDR_QUOTA
''' +
bld.env['dmapi_lib'] +
bld.env['legacy_quota_libs'] +
--
2.10.2
From 035759b8ac6525a6896544a99e16ed97e3ffb724 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 1 Mar 2017 18:58:21 +0000
Subject: [PATCH 05/11] s3/smbd: Add support for SetInfo/SMB2_0_INFO_QUOTA
[MS-SMB2] 2.2.39
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/smbd/smb2_setinfo.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
index db00ba0..21c8746 100644
--- a/source3/smbd/smb2_setinfo.c
+++ b/source3/smbd/smb2_setinfo.c
@@ -28,6 +28,7 @@
#include "../librpc/gen_ndr/open_files.h"
#include "source3/lib/dbwrap/dbwrap_watch.h"
#include "messages.h"
+#include "librpc/gen_ndr/ndr_quota.h"
static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@@ -567,6 +568,37 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
break;
}
+ case 0x04:/* SMB2_SETINFO_QUOTA */
+ {
+ struct file_quota_information info = {0};
+ SMB_NTQUOTA_STRUCT qt = {0};
+ enum ndr_err_code err;
+ if (!fsp->fake_file_handle) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ err = ndr_pull_struct_blob(
+ &in_input_buffer, state, &info,
+ (ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return tevent_req_post(req, ev);
+ }
+
+ qt.usedspace = info.quota_used;
+
+ qt.softlim = info.quota_threshold;
+
+ qt.hardlim = info.quota_limit;
+
+ qt.sid = info.sid;
+ if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &qt.sid, &qt)!=0) {
+ tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+ return tevent_req_post(req, ev);
+ }
+ status = NT_STATUS_OK;
+ break;
+ }
default:
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
--
2.10.2
From 356ddd94b906004c28175f8f49f4ba25d39374d6 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 1 Mar 2017 18:22:48 +0000
Subject: [PATCH 06/11] s3/smbd: Use ndr generated structures and routines for
SMB1 SET_QUOTA msg
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/smbd/nttrans.c | 82 +++++++++++++++++++++++---------------------------
1 file changed, 38 insertions(+), 44 deletions(-)
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index ee9876e..86c88f9 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -2958,10 +2958,13 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
char *pdata = *ppdata;
int data_len=0,param_len=0;
SMB_NTQUOTA_STRUCT qt;
- size_t sid_len;
+ struct file_quota_information info = {0};
+ enum ndr_err_code err;
struct dom_sid sid;
+ DATA_BLOB inblob;
files_struct *fsp = NULL;
-
+ TALLOC_CTX *ctx = NULL;
+ NTSTATUS status = NT_STATUS_OK;
ZERO_STRUCT(qt);
/* access check */
@@ -2969,8 +2972,8 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
DEBUG(1,("set_user_quota: access_denied service [%s] user "
"[%s]\n", lp_servicename(talloc_tos(), SNUM(conn)),
conn->session_info->unix_info->unix_name));
- reply_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
+ status = NT_STATUS_ACCESS_DENIED;
+ goto error;
}
/*
@@ -2979,67 +2982,58 @@ static void call_nt_transact_set_user_quota(connection_struct *conn,
if (parameter_count < 2) {
DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= 2 bytes parameters\n",parameter_count));
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto error;
}
/* maybe we can check the quota_fnum */
fsp = file_fsp(req, SVAL(params,0));
if (!check_fsp_ntquota_handle(conn, req, fsp)) {
DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
- reply_nterror(req, NT_STATUS_INVALID_HANDLE);
- return;
+ status = NT_STATUS_INVALID_HANDLE;
+ goto error;
}
- if (data_count < 40) {
- DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %d bytes data\n",data_count,40));
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
+ ctx = talloc_init("set_user_quota");
+ if (!ctx) {
+ status = NT_STATUS_NO_MEMORY;
+ goto error;
}
+ inblob.data = (uint8_t*)pdata;
+ inblob.length = data_count;
- /* offset to next quota record.
- * 4 bytes IVAL(pdata,0)
- * unused here...
- */
+ err = ndr_pull_struct_blob(
+ &inblob,
+ ctx,
+ &info,
+ (ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
- /* sid len */
- sid_len = IVAL(pdata,4);
-
- if (data_count < 40+sid_len || (40+sid_len < sid_len)) {
- DEBUG(0,("TRANSACT_SET_USER_QUOTA: requires %d >= %lu bytes data\n",data_count,(unsigned long)40+sid_len));
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DEBUG(0,("TRANSACT_SET_USER_QUOTA: failed to pull "
+ "file_quota_information\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto error;
}
+ qt.usedspace = info.quota_used;
- /* unknown 8 bytes in pdata
- * maybe its the change time in NTTIME
- */
+ qt.softlim = info.quota_threshold;
- /* the used space 8 bytes (uint64_t)*/
- qt.usedspace = BVAL(pdata,16);
+ qt.hardlim = info.quota_limit;
- /* the soft quotas 8 bytes (uint64_t)*/
- qt.softlim = BVAL(pdata,24);
-
- /* the hard quotas 8 bytes (uint64_t)*/
- qt.hardlim = BVAL(pdata,32);
-
- if (!sid_parse((const uint8_t *)(pdata+40), sid_len, &sid)) {
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
- }
-
- DEBUGADD(8,("SID: %s\n", sid_string_dbg(&sid)));
-
- /* 44 unknown bytes left... */
+ sid = info.sid;
if (vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) {
- reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return;
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto error;
}
send_nt_replies(conn, req, NT_STATUS_OK, params, param_len,
pdata, data_len);
+ TALLOC_FREE(ctx);
+ return;
+error:
+ TALLOC_FREE(ctx);
+ reply_nterror(req, status);
}
#endif /* HAVE_SYS_QUOTAS */
--
2.10.2
From 93a84b7fa59e7a843cbcebddc2b96c9b46df836f Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Mon, 13 Mar 2017 10:22:24 +0000
Subject: [PATCH 07/11] s3/smbd: Leverage the new common code
smbd_do_query_getinfo_quota.
Make both SMB1 & SMB2 use common code for quota queries.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/smbd/nttrans.c | 350 +++++++++++++++++--------------------------------
1 file changed, 117 insertions(+), 233 deletions(-)
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 86c88f9..fe18966 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -2573,6 +2573,7 @@ NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
info->start_sid_length,
info->start_sid_offset);
+ /* #TODO #FIXME limit/range check etc. the lenght/offset values */
qt_handle =
(SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data;
@@ -2664,6 +2665,27 @@ done:
Reply to get user quota
****************************************************************************/
+/*
+ * convert nttrans_query_quota_params values to conform to smb2 expectations
+ * and return struct smb2_query_quota_info to use in
+ * smbd_do_query_getinfo_quota
+ */
+static void convert_quoata_trans_param(
+ struct nttrans_query_quota_params *in,
+ struct smb2_query_quota_info *out_smb2_info)
+{
+ ZERO_STRUCTP(out_smb2_info);
+ out_smb2_info->return_single = in->return_single_entry;
+ out_smb2_info->restart_scan = in->restart_scan;
+ if (in->sid_list_length) {
+ out_smb2_info->sid_list_length = in->sid_list_length;
+ out_smb2_info->start_sid_offset = 0;
+ out_smb2_info->start_sid_length = 0;
+ } else if (in->start_sid_length) {
+ out_smb2_info->sid_list_length = in->start_sid_length;
+ }
+}
+
static void call_nt_transact_get_user_quota(connection_struct *conn,
struct smb_request *req,
uint16_t **ppsetup,
@@ -2677,267 +2699,129 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
NTSTATUS nt_status = NT_STATUS_OK;
char *params = *ppparams;
char *pdata = *ppdata;
- char *entry;
int data_len=0,param_len=0;
- int qt_len=0;
- int entry_len = 0;
files_struct *fsp = NULL;
- uint16_t level = 0;
- size_t sid_len;
- struct dom_sid sid;
- bool start_enum = True;
SMB_NTQUOTA_STRUCT qt;
- SMB_NTQUOTA_LIST *tmp_list;
- SMB_NTQUOTA_HANDLE *qt_handle = NULL;
+ DATA_BLOB blob;
+ struct nttrans_query_quota_params info;
+ enum ndr_err_code err;
+ TALLOC_CTX *tmp_ctx = NULL;
+ uint32_t resp_len = 0;
+ uint8_t *resp_data = 0;
+ struct smb2_query_quota_info info_smb2;
+ struct ndr_pull *ndr_pull = NULL;
ZERO_STRUCT(qt);
+ ZERO_STRUCT(info);
+ tmp_ctx = talloc_init("ntquota_list");
+ if (!tmp_ctx) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
/* access check */
if (get_current_uid(conn) != sec_initial_uid()) {
DEBUG(1,("get_user_quota: access_denied service [%s] user "
"[%s]\n", lp_servicename(talloc_tos(), SNUM(conn)),
conn->session_info->unix_info->unix_name));
- reply_nterror(req, NT_STATUS_ACCESS_DENIED);
- return;
+ nt_status = NT_STATUS_ACCESS_DENIED;
+ goto error;
}
- /*
- * Ensure minimum number of parameters sent.
- */
+ blob.data = (uint8_t*)params;
+ blob.length = parameter_count;
- if (parameter_count < 4) {
- DEBUG(0,("TRANSACT_GET_USER_QUOTA: requires %d >= 4 bytes parameters\n",parameter_count));
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
- }
+ ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx);
- /* maybe we can check the quota_fnum */
- fsp = file_fsp(req, SVAL(params,0));
- if (!check_fsp_ntquota_handle(conn, req, fsp)) {
- DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
- reply_nterror(req, NT_STATUS_INVALID_HANDLE);
- return;
+ if (!ndr_pull) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto error;
}
- /* the NULL pointer checking for fsp->fake_file_handle->pd
- * is done by CHECK_NTQUOTA_HANDLE_OK()
- */
- qt_handle = (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data;
-
- level = SVAL(params,2);
-
- /* unknown 12 bytes leading in params */
-
- switch (level) {
- case TRANSACT_GET_USER_QUOTA_LIST_CONTINUE:
- /* seems that we should continue with the enum here --metze */
-
- if (qt_handle->quota_list!=NULL &&
- qt_handle->tmp_list==NULL) {
-
- /* free the list */
- free_ntquota_list(&(qt_handle->quota_list));
-
- /* Realloc the size of parameters and data we will return */
- param_len = 4;
- params = nttrans_realloc(ppparams, param_len);
- if(params == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
-
- data_len = 0;
- SIVAL(params,0,data_len);
-
- break;
- }
-
- start_enum = False;
-
- case TRANSACT_GET_USER_QUOTA_LIST_START:
-
- if (qt_handle->quota_list==NULL &&
- qt_handle->tmp_list==NULL) {
- start_enum = True;
- }
-
- if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) {
- reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
- return;
- }
-
- /* Realloc the size of parameters and data we will return */
- param_len = 4;
- params = nttrans_realloc(ppparams, param_len);
- if(params == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
-
- /* we should not trust the value in max_data_count*/
- max_data_count = MIN(max_data_count,2048);
-
- pdata = nttrans_realloc(ppdata, max_data_count);/* should be max data count from client*/
- if(pdata == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
-
- entry = pdata;
-
- /* set params Size of returned Quota Data 4 bytes*/
- /* but set it later when we know it */
-
- /* for each entry push the data */
-
- if (start_enum) {
- qt_handle->tmp_list = qt_handle->quota_list;
- }
-
- tmp_list = qt_handle->tmp_list;
-
- for (;((tmp_list!=NULL)&&((qt_len +40+SID_MAX_SIZE)<max_data_count));
- tmp_list=tmp_list->next,entry+=entry_len,qt_len+=entry_len) {
-
- sid_len = ndr_size_dom_sid(
- &tmp_list->quotas->sid, 0);
- entry_len = 40 + sid_len;
-
- /* nextoffset entry 4 bytes */
- SIVAL(entry,0,entry_len);
-
- /* then the len of the SID 4 bytes */
- SIVAL(entry,4,sid_len);
-
- /* unknown data 8 bytes uint64_t */
- SBIG_UINT(entry,8,(uint64_t)0); /* this is not 0 in windows...-metze*/
-
- /* the used disk space 8 bytes uint64_t */
- SBIG_UINT(entry,16,tmp_list->quotas->usedspace);
+ err = ndr_pull_struct_blob(&blob, tmp_ctx, &info,
+ (ndr_pull_flags_fn_t)ndr_pull_nttrans_query_quota_params);
- /* the soft quotas 8 bytes uint64_t */
- SBIG_UINT(entry,24,tmp_list->quotas->softlim);
-
- /* the hard quotas 8 bytes uint64_t */
- SBIG_UINT(entry,32,tmp_list->quotas->hardlim);
-
- /* and now the SID */
- sid_linearize((uint8_t *)(entry+40), sid_len,
- &tmp_list->quotas->sid);
- }
-
- qt_handle->tmp_list = tmp_list;
-
- /* overwrite the offset of the last entry */
- SIVAL(entry-entry_len,0,0);
-
- data_len = 4+qt_len;
- /* overwrite the params quota_data_len */
- SIVAL(params,0,data_len);
-
- break;
-
- case TRANSACT_GET_USER_QUOTA_FOR_SID:
-
- /* unknown 4 bytes IVAL(pdata,0) */
-
- if (data_count < 8) {
- DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %d bytes data\n",data_count,8));
- reply_nterror(req, NT_STATUS_INVALID_LEVEL);
- return;
- }
-
- sid_len = IVAL(pdata,4);
- /* Ensure this is less than 1mb. */
- if (sid_len > (1024*1024)) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
-
- if (data_count < 8+sid_len) {
- DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: requires %d >= %lu bytes data\n",data_count,(unsigned long)(8+sid_len)));
- reply_nterror(req, NT_STATUS_INVALID_LEVEL);
- return;
- }
-
- data_len = 4+40+sid_len;
-
- if (max_data_count < data_len) {
- DEBUG(0,("TRANSACT_GET_USER_QUOTA_FOR_SID: max_data_count(%d) < data_len(%d)\n",
- max_data_count, data_len));
- param_len = 4;
- SIVAL(params,0,data_len);
- data_len = 0;
- nt_status = NT_STATUS_BUFFER_TOO_SMALL;
- break;
- }
-
- if (!sid_parse((const uint8_t *)(pdata+8), sid_len,
- &sid)) {
- reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
- return;
- }
-
- nt_status = vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE,
- &sid, &qt);
- if (!NT_STATUS_IS_OK(nt_status)) {
- reply_nterror(req, nt_status);
- return;
- }
-
- /* Realloc the size of parameters and data we will return */
- param_len = 4;
- params = nttrans_realloc(ppparams, param_len);
- if(params == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
-
- pdata = nttrans_realloc(ppdata, data_len);
- if(pdata == NULL) {
- reply_nterror(req, NT_STATUS_NO_MEMORY);
- return;
- }
-
- entry = pdata;
-
- /* set params Size of returned Quota Data 4 bytes*/
- SIVAL(params,0,data_len);
-
- /* nextoffset entry 4 bytes */
- SIVAL(entry,0,0);
-
- /* then the len of the SID 4 bytes */
- SIVAL(entry,4,sid_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DEBUG(0,("TRANSACT_GET_USER_QUOTA: failed to pull "
+ "query_quota_params."));
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+ DBG_DEBUG("info.return_single_entry = %d, info.restart_scan = %d, "
+ "info.sid_list_length = %d, info.start_sid_length = %d, "
+ "info.start_sid_offset = %d\n",
+ info.return_single_entry,
+ info.restart_scan,
+ info.sid_list_length,
+ info.start_sid_length,
+ info.start_sid_offset);
+
+
+ if (info.start_sid_length && info.start_sid_offset) {
+ if (info.start_sid_offset > data_count) {
+ DBG_ERR("TRANSACT_GET_USER_QUOTA: illegal sid_offset "
+ "0x%x into sid buffer (of length 0x%x)\n",
+ info.start_sid_offset, (uint32_t)blob.length);
+ nt_status = NT_STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+ blob.data = (uint8_t*)pdata + info.start_sid_offset ;
+ } else {
+ blob.data = (uint8_t*)pdata + ndr_pull->offset;
+ }
- /* unknown data 8 bytes uint64_t */
- SBIG_UINT(entry,8,(uint64_t)0); /* this is not 0 in windows...-mezte*/
+ blob.length = data_count;
- /* the used disk space 8 bytes uint64_t */
- SBIG_UINT(entry,16,qt.usedspace);
+ /* populate smb2 equivelant structure */
+ convert_quoata_trans_param(&info, &info_smb2);
- /* the soft quotas 8 bytes uint64_t */
- SBIG_UINT(entry,24,qt.softlim);
+ /* maybe we can check the quota_fnum */
+ fsp = file_fsp(req, info.fid);
+ if (!check_fsp_ntquota_handle(conn, req, fsp)) {
+ DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
+ nt_status = NT_STATUS_INVALID_HANDLE;
+ goto error;
+ }
+ nt_status = smbd_do_query_getinfo_quota(tmp_ctx,
+ fsp,
+ &info_smb2,
+ &blob,
+ max_data_count,
+ &resp_data,
+ &resp_len);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ /*
+ * smb1 doesn't send NT_STATUS_NO_MORE_ENTRIES so swallow
+ * this status.
+ */
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES)) {
+ nt_status = NT_STATUS_OK;
+ } else {
+ goto error;
+ }
+ }
- /* the hard quotas 8 bytes uint64_t */
- SBIG_UINT(entry,32,qt.hardlim);
+ param_len = 4;
+ params = nttrans_realloc(ppparams, param_len);
+ if(params == NULL) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
- /* and now the SID */
- sid_linearize((uint8_t *)(entry+40), sid_len, &sid);
+ SIVAL(params, 0, param_len);
- break;
+ data_len = resp_len;
+ pdata = nttrans_realloc(ppdata, data_len);
- default:
- DEBUG(0, ("do_nt_transact_get_user_quota: %s: unknown "
- "level 0x%04hX\n",
- fsp_fnum_dbg(fsp), level));
- reply_nterror(req, NT_STATUS_INVALID_LEVEL);
- return;
- break;
- }
+ memcpy(pdata, resp_data, data_len);
+ TALLOC_FREE(tmp_ctx);
send_nt_replies(conn, req, nt_status, params, param_len,
pdata, data_len);
+ return;
+error:
+ TALLOC_FREE(tmp_ctx);
+ reply_nterror(req, nt_status);
}
/****************************************************************************
--
2.10.2
From 8d3c7b97aab21f6793eed3ea9c03b10ecdc98ebd Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 1 Mar 2017 14:19:14 +0000
Subject: [PATCH 08/11] s3/libsmb: Use ndr generated structures & routines for
SMB[1|2] quota msgs.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/libsmb/cli_smb2_fnum.c | 83 ++++++++++++++++++++++++++++--------------
source3/libsmb/cliquota.c | 74 ++++++++++++++-----------------------
source3/wscript_build | 1 +
3 files changed, 83 insertions(+), 75 deletions(-)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 7977bea..25aa32d 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -41,6 +41,7 @@
#include "lib/util_ea.h"
#include "librpc/gen_ndr/ndr_ioctl.h"
#include "ntioctl.h"
+#include "librpc/gen_ndr/ndr_quota.h"
struct smb2_hnd {
uint64_t fid_persistent;
@@ -2395,12 +2396,16 @@ NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
{
NTSTATUS status;
DATA_BLOB inbuf = data_blob_null;
+ DATA_BLOB info_blob = 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;
+ struct smb2_query_quota_info query = {0};
+ struct file_get_quota_info info = {0};
+ enum ndr_err_code err;
+ struct ndr_push *ndr_push = NULL;
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
@@ -2422,27 +2427,49 @@ NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
sid_len = ndr_size_dom_sid(&pqt->sid, 0);
- inbuf = data_blob_talloc_zero(frame, 24 + sid_len);
- if (inbuf.data == NULL) {
+ query.return_single = 1;
+ if (sid_len < 0) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ndr_push = ndr_push_init_ctx(frame);
+ info.next_entry_offset = 0;
+ info.sid_length = sid_len;
+ info.sid = pqt->sid;
+
+ err = ndr_push_struct_blob(
+ &info_blob,
+ frame,
+ &info,
+ (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ query.sid_list_length = info_blob.length;
+ ndr_push = ndr_push_init_ctx(frame);
+ if (!ndr_push) {
status = NT_STATUS_NO_MEMORY;
goto fail;
}
- buf = inbuf.data;
+ err = ndr_push_smb2_query_quota_info(ndr_push,
+ NDR_SCALARS | NDR_BUFFERS,
+ &query);
- 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;
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ status = NT_STATUS_INTERNAL_ERROR;
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);
+
+ err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
+ info_blob.length);
+
+ inbuf.data = ndr_push->data;
+ inbuf.length = ndr_push->offset;
status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
cli->smb2.tcon, 4, /* in_info_type */
@@ -2487,7 +2514,8 @@ NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
DATA_BLOB outbuf = data_blob_null;
struct smb2_hnd *ph = NULL;
TALLOC_CTX *frame = talloc_stackframe();
- uint8_t *buf;
+ struct smb2_query_quota_info info = {0};
+ enum ndr_err_code err;
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
@@ -2507,20 +2535,19 @@ NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
goto cleanup;
}
- inbuf = data_blob_talloc_zero(frame, 16);
- if (inbuf.data == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto cleanup;
- }
- buf = inbuf.data;
+ info.restart_scan = first ? 1 : 0;
+
+ err = ndr_push_struct_blob(
+ &inbuf,
+ frame,
+ &info,
+ (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
- 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 */
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto cleanup;
+ }
status = smb2cli_query_info(cli->conn, cli->timeout, cli->smb2.session,
cli->smb2.tcon, 4, /* in_info_type */
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index e22ccdd..c0e163c 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -24,6 +24,7 @@
#include "../libcli/security/security.h"
#include "trans2.h"
#include "../libcli/smb/smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_quota.h"
NTSTATUS cli_get_quota_handle(struct cli_state *cli, uint16_t *quota_fnum)
{
@@ -75,61 +76,40 @@ bool parse_user_quota_record(const uint8_t *rdata,
unsigned int *offset,
SMB_NTQUOTA_STRUCT *pqt)
{
- int sid_len;
- SMB_NTQUOTA_STRUCT qt;
-
- ZERO_STRUCT(qt);
-
- if (!rdata||!offset||!pqt) {
- smb_panic("parse_quota_record: called with NULL POINTER!");
- }
-
- if (rdata_count < 40) {
- return False;
- }
-
- /* offset to next quota record.
- * 4 bytes IVAL(rdata,0)
- * unused here...
- */
- *offset = IVAL(rdata,0);
-
- /* sid len */
- sid_len = IVAL(rdata,4);
- if (40 + sid_len < 40) {
- return false;
- }
+ struct file_quota_information info = {0};
+ TALLOC_CTX *frame = talloc_stackframe();
+ DATA_BLOB blob;
+ enum ndr_err_code err;
+ bool result;
- if (rdata_count < 40+sid_len) {
- return False;
- }
+ blob.data = discard_const_p(uint8_t, rdata);
+ blob.length = rdata_count;
+ err = ndr_pull_struct_blob(
+ &blob,
+ frame,
+ &info,
+ (ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
- if (*offset != 0 && *offset < 40 + sid_len) {
- return false;
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ result = false;
+ goto out;
}
- /* unknown 8 bytes in pdata
- * maybe its the change time in NTTIME
- */
-
- /* the used space 8 bytes (uint64_t)*/
- qt.usedspace = BVAL(rdata,16);
-
- /* the soft quotas 8 bytes (uint64_t)*/
- qt.softlim = BVAL(rdata,24);
-
- /* the hard quotas 8 bytes (uint64_t)*/
- qt.hardlim = BVAL(rdata,32);
+ *offset = info.next_entry_offset;
- if (!sid_parse(rdata+40,sid_len,&qt.sid)) {
- return false;
- }
+ ZERO_STRUCTP(pqt);
+ pqt->usedspace = info.quota_used;
- qt.qtype = SMB_USER_QUOTA_TYPE;
+ pqt->softlim = info.quota_threshold;
- *pqt = qt;
+ pqt->hardlim = info.quota_limit;
- return True;
+ pqt->qtype = SMB_USER_QUOTA_TYPE;
+ pqt->sid = info.sid;
+ result = true;
+out:
+ TALLOC_FREE(frame);
+ return result;
}
NTSTATUS parse_user_quota_list(const uint8_t *curdata,
diff --git a/source3/wscript_build b/source3/wscript_build
index 3414761..54234ad 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -487,6 +487,7 @@ bld.SAMBA3_LIBRARY('libsmb',
LIBTSOCKET
KRBCLIENT
NDR_IOCTL
+ NDR_QUOTA
cli_smb_common
util_cmdline
tevent
--
2.10.2
From 59ec0a3626d442f879b2b453c79e6d50c6a841f0 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 1 Mar 2017 16:51:06 +0000
Subject: [PATCH 09/11] s3/libsmb: Modify build_user_quota_buffer with ndr
structs and push/pull funcs.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/libsmb/cliquota.c | 149 ++++++++++++++++++++--------------------------
1 file changed, 63 insertions(+), 86 deletions(-)
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index c0e163c..3159265 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -197,111 +197,80 @@ NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list,
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;
-
+ int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+ struct ndr_push *header_ndr = ndr_push_init_ctx(mem_ctx);
+ uint32_t start_offset = 0;
+ uint32_t num_pushed = 0;
+ uint32_t next_align = 0;
+ bool max_data_exceeded = false;
if (qt_list == NULL) {
- status = NT_STATUS_OK;
- *outbuf = data_blob_null;
- if (end_ptr) {
- *end_ptr = NULL;
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+ for (;qt_list!=NULL; qt_list=qt_list->next, num_pushed++) {
+ struct file_quota_information info;
+ enum ndr_err_code err;
+ ZERO_STRUCT(info);
+ info.sid_length = ndr_size_dom_sid(&qt_list->quotas->sid, 0);
+
+ if (maxlen && ((header_ndr->offset - next_align)
+ + sizeof(info.next_entry_offset)
+ + sizeof(info.sid_length)
+ + sizeof(info.change_time)
+ + sizeof(info.quota_used)
+ + sizeof(info.quota_threshold)
+ + sizeof(info.quota_limit)
+ + info.sid_length) > maxlen) {
+ max_data_exceeded = true;
+ break;
}
- return NT_STATUS_OK;
- }
+ start_offset = header_ndr->offset;
- for (qtl = qt_list; qtl != NULL; qtl = qtl->next) {
+ info.sid = qt_list->quotas->sid;
+ info.quota_used = qt_list->quotas->usedspace;
+ info.quota_threshold = qt_list->quotas->softlim;
+ info.quota_limit = qt_list->quotas->hardlim;
- 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;
+ err = ndr_push_file_quota_information(header_ndr,
+ ndr_flags,
+ &info);
- if (qt_len + entry_len < qt_len) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto fail;
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DBG_DEBUG("Failed to pull the quota sid\n");
+ return NT_STATUS_INTERNAL_ERROR;
}
- qt_len += entry_len;
- }
- if (maxlen > 0 && qt_len > maxlen) {
- qt_len = maxlen;
- }
+ /* pidl will align to 8 bytes due to 8 byte members*/
+ next_align = header_ndr->offset;
+ ndr_push_align(header_ndr, 8);
+ next_align = header_ndr->offset - next_align;
+ info.next_entry_offset = header_ndr->offset - start_offset;
- qbuf = data_blob_talloc_zero(mem_ctx, qt_len);
- if (qbuf.data == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
+ /* write nextentryoffset to the buffer too */
+ SIVAL(header_ndr->data, start_offset, info.next_entry_offset);
}
- 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);
+ outbuf->length = header_ndr->offset - next_align;
+ outbuf->data = header_ndr->data;
- /* 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);
+ if (num_pushed) {
+ /* terminate the list */
+ SIVAL(header_ndr->data, start_offset, 0);
}
- /* 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
+ /*
+ * if we failed to write a single file_quota_information
+ * issue BUFFER_TOO_SMALL
*/
- qbuf.length = qt_len;
- *outbuf = qbuf;
- qbuf = data_blob_null;
- status = NT_STATUS_OK;
+ if (max_data_exceeded && num_pushed < 1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
if (end_ptr) {
*end_ptr = qt_list;
}
-fail:
- data_blob_free(&qbuf);
-
- return status;
+ return NT_STATUS_OK;
}
NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx,
@@ -422,7 +391,15 @@ cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST *qtl)
status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL);
if (!NT_STATUS_IS_OK(status)) {
- goto cleanup;
+ /*
+ * smb1 doesn't send NT_STATUS_NO_MORE_ENTRIES so swallow
+ * this status.
+ */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
+ status = NT_STATUS_OK;
+ } else {
+ goto cleanup;
+ }
}
SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA);
--
2.10.2
From 8e7418a25bdf1a7cdc79a44f3d925d015291a8ea Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 8 Mar 2017 14:27:27 +0000
Subject: [PATCH 10/11] s3/script/test: modify existing smbcquota test to use
SMB2 in addition to SMB1.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/script/tests/test_dfree_quota.sh | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/source3/script/tests/test_dfree_quota.sh b/source3/script/tests/test_dfree_quota.sh
index 6e227c4..43f3623 100755
--- a/source3/script/tests/test_dfree_quota.sh
+++ b/source3/script/tests/test_dfree_quota.sh
@@ -135,13 +135,21 @@ test_smbcquotas() {
conf="$2"
user="$3"
expected="$4"
+ proto="$5"
shift
shift
shift
shift
+ shift
subunit_start_test "$name"
setup_conf "$conf" "."
- output=$($VALGRIND $smbcquotas //$SERVER/dfq $@ 2>/dev/null | tr '\\' '/')
+ if [ "$proto" = "smb2" ]; then
+ mproto="-m SMB2"
+ else
+ mproto="-m SMB1"
+ fi
+
+ output=$($VALGRIND $smbcquotas $mproto //$SERVER/dfq $@ 2>/dev/null | tr '\\' '/')
status=$?
if [ "$status" = "0" ]; then
received=$(echo "$output" | awk "/$SERVER\\/$user/ {printf \"%s%s%s\", \$3, \$4, \$5}")
@@ -162,7 +170,9 @@ test_smbclient_dfree "Test dfree subdir SMB3 no quota" dfq "subdir1" "conf1 . co
test_smbclient_dfree "Test dfree subdir NT1 no quota" dfq "subdir1" "conf1 . conf2 subdir1" "10 1024. 5" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
test_smbclient_dfree "Test large disk" dfq "." "conf3 ." "1125899906842624 1024. 3000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
#basic quota test (SMB1 only)
-test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
+test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" "smb1" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=NT1 || failed=`expr $failed + 1`
+#basic quota test (SMB2 only)
+test_smbcquotas "Test user quota" confq1 $USERNAME "40960/4096000/3072000" "smb2" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB2 || failed=`expr $failed + 1`
#quota limit > disk size, remaining quota > disk free
test_smbclient_dfree "Test dfree share root df vs quota case 1" dfq "." "confdfq1 ." "80 1024. 40" -U$USERNAME%$PASSWORD --option=clientmaxprotocol=SMB3 || failed=`expr $failed + 1`
--
2.10.2
From 87e05b2ada90d830f78f95a6d36fb33ea7e4f095 Mon Sep 17 00:00:00 2001
From: Noel Power <noel.power at suse.com>
Date: Wed, 8 Mar 2017 17:22:40 +0000
Subject: [PATCH 11/11] s3/libsmb: new fill_quota_buffer common function for
client/server use.
Signed-off-by: Noel Power <noel.power at suse.com>
---
source3/libsmb/cli_smb2_fnum.c | 87 ++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 7 +++
source3/libsmb/cliquota.c | 80 +++------------------------
source3/smbd/nttrans.c | 119 +++++------------------------------------
4 files changed, 112 insertions(+), 181 deletions(-)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 25aa32d..80a2bdd 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -3674,3 +3674,90 @@ NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
TALLOC_FREE(frame);
return status;
}
+
+ NTSTATUS fill_quota_buffer(TALLOC_CTX *mem_ctx,
+ SMB_NTQUOTA_LIST *tmp_list,
+ bool return_single,
+ uint32_t max_data,
+ DATA_BLOB *blob,
+ SMB_NTQUOTA_LIST **end_ptr)
+{
+ int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
+ struct ndr_push *header_ndr = ndr_push_init_ctx(mem_ctx);
+ uint32_t start_offset = 0;
+ uint32_t num_pushed = 0;
+ uint32_t next_align = 0;
+ bool max_data_exceeded = false;
+
+ if (tmp_list == NULL) {
+ return NT_STATUS_NO_MORE_ENTRIES;
+ }
+ for (;tmp_list!=NULL; tmp_list=tmp_list->next, num_pushed++) {
+ struct file_quota_information info;
+ enum ndr_err_code err;
+ ZERO_STRUCT(info);
+ info.sid_length = ndr_size_dom_sid(&tmp_list->quotas->sid, 0);
+
+ if (max_data && ((header_ndr->offset - next_align)
+ + sizeof(info.next_entry_offset)
+ + sizeof(info.sid_length)
+ + sizeof(info.change_time)
+ + sizeof(info.quota_used)
+ + sizeof(info.quota_threshold)
+ + sizeof(info.quota_limit)
+ + info.sid_length) > max_data) {
+ max_data_exceeded = true;
+ break;
+ }
+ start_offset = header_ndr->offset;
+
+ info.sid = tmp_list->quotas->sid;
+ info.quota_used = tmp_list->quotas->usedspace;
+ info.quota_threshold = tmp_list->quotas->softlim;
+ info.quota_limit = tmp_list->quotas->hardlim;
+
+ err = ndr_push_file_quota_information(header_ndr,
+ ndr_flags,
+ &info);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ DBG_DEBUG("Failed to pull the quota sid\n");
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* pidl will align to 8 bytes due to 8 byte members*/
+ next_align = header_ndr->offset;
+ ndr_push_align(header_ndr, 8);
+ next_align = header_ndr->offset - next_align;
+ info.next_entry_offset = header_ndr->offset - start_offset;
+
+ if (return_single) {
+ break;
+ }
+
+ /* write nextentryoffset to the buffer too */
+ SIVAL(header_ndr->data, start_offset, info.next_entry_offset);
+ }
+
+ if (end_ptr) {
+ *end_ptr = tmp_list;
+ }
+
+ blob->length = header_ndr->offset - next_align;
+ blob->data = header_ndr->data;
+
+ if (num_pushed) {
+ /* terminate the list */
+ SIVAL(header_ndr->data, start_offset, 0);
+ }
+
+ /*
+ * if we failed to write a single file_quota_information
+ * issue BUFFER_TOO_SMALL
+ */
+ if (max_data_exceeded && num_pushed < 1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 12c42a2..e5a3ca1 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -211,4 +211,11 @@ NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
uint16_t fnum,
uint64_t newsize);
+
+NTSTATUS fill_quota_buffer(TALLOC_CTX *mem_ctx,
+ SMB_NTQUOTA_LIST *tmp_list,
+ bool return_single,
+ uint32_t max_data,
+ DATA_BLOB *blob,
+ SMB_NTQUOTA_LIST **end_ptr);
#endif /* __SMB2CLI_FNUM_H__ */
diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c
index 3159265..fca16d6 100644
--- a/source3/libsmb/cliquota.c
+++ b/source3/libsmb/cliquota.c
@@ -197,80 +197,12 @@ NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list,
DATA_BLOB *outbuf,
SMB_NTQUOTA_LIST **end_ptr)
{
- int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
- struct ndr_push *header_ndr = ndr_push_init_ctx(mem_ctx);
- uint32_t start_offset = 0;
- uint32_t num_pushed = 0;
- uint32_t next_align = 0;
- bool max_data_exceeded = false;
- if (qt_list == NULL) {
- return NT_STATUS_NO_MORE_ENTRIES;
- }
- for (;qt_list!=NULL; qt_list=qt_list->next, num_pushed++) {
- struct file_quota_information info;
- enum ndr_err_code err;
- ZERO_STRUCT(info);
- info.sid_length = ndr_size_dom_sid(&qt_list->quotas->sid, 0);
-
- if (maxlen && ((header_ndr->offset - next_align)
- + sizeof(info.next_entry_offset)
- + sizeof(info.sid_length)
- + sizeof(info.change_time)
- + sizeof(info.quota_used)
- + sizeof(info.quota_threshold)
- + sizeof(info.quota_limit)
- + info.sid_length) > maxlen) {
- max_data_exceeded = true;
- break;
- }
- start_offset = header_ndr->offset;
-
- info.sid = qt_list->quotas->sid;
- info.quota_used = qt_list->quotas->usedspace;
- info.quota_threshold = qt_list->quotas->softlim;
- info.quota_limit = qt_list->quotas->hardlim;
-
- err = ndr_push_file_quota_information(header_ndr,
- ndr_flags,
- &info);
-
- if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
- DBG_DEBUG("Failed to pull the quota sid\n");
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- /* pidl will align to 8 bytes due to 8 byte members*/
- next_align = header_ndr->offset;
- ndr_push_align(header_ndr, 8);
- next_align = header_ndr->offset - next_align;
- info.next_entry_offset = header_ndr->offset - start_offset;
-
- /* write nextentryoffset to the buffer too */
- SIVAL(header_ndr->data, start_offset, info.next_entry_offset);
- }
-
-
- outbuf->length = header_ndr->offset - next_align;
- outbuf->data = header_ndr->data;
-
- if (num_pushed) {
- /* terminate the list */
- SIVAL(header_ndr->data, start_offset, 0);
- }
-
- /*
- * if we failed to write a single file_quota_information
- * issue BUFFER_TOO_SMALL
- */
- if (max_data_exceeded && num_pushed < 1) {
- return NT_STATUS_BUFFER_TOO_SMALL;
- }
-
- if (end_ptr) {
- *end_ptr = qt_list;
- }
-
- return NT_STATUS_OK;
+ return fill_quota_buffer(mem_ctx,
+ qt_list,
+ false,
+ maxlen,
+ outbuf,
+ end_ptr);
}
NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx,
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index fe18966..ef3706c 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -2454,105 +2454,6 @@ done:
return err;
}
-static NTSTATUS fill_quota_buffer(TALLOC_CTX *mem_ctx,
- SMB_NTQUOTA_HANDLE *qt_handle,
- bool rescan,
- bool return_single,
- uint32_t max_data,
- uint8_t **data,
- uint32_t *datalen)
-{
- SMB_NTQUOTA_STRUCT qt;
- SMB_NTQUOTA_LIST *tmp_list;
- int ndr_flags = NDR_SCALARS | NDR_BUFFERS;
- struct ndr_push *header_ndr = ndr_push_init_ctx(mem_ctx);
- uint32_t start_offset = 0;
- uint32_t num_pushed = 0;
- uint32_t next_align = 0;
- bool max_data_exceeded = false;
-
- ZERO_STRUCT(qt);
- *data = NULL;
- *datalen = 0;
-
- if (rescan) {
- tmp_list = qt_handle->quota_list;
- } else {
- tmp_list = qt_handle->tmp_list;
- }
-
- if (tmp_list == NULL) {
- return NT_STATUS_NO_MORE_ENTRIES;
- }
- for (;tmp_list!=NULL; tmp_list=tmp_list->next, num_pushed++) {
- struct file_quota_information info;
- enum ndr_err_code err;
- ZERO_STRUCT(info);
- info.sid_length = ndr_size_dom_sid(&tmp_list->quotas->sid, 0);
-
- if (((header_ndr->offset - next_align)
- + sizeof(info.next_entry_offset)
- + sizeof(info.sid_length)
- + sizeof(info.change_time)
- + sizeof(info.quota_used)
- + sizeof(info.quota_threshold)
- + sizeof(info.quota_limit)
- + info.sid_length) > max_data) {
- max_data_exceeded = true;
- break;
- }
- start_offset = header_ndr->offset;
-
- info.sid = tmp_list->quotas->sid;
- info.quota_used = tmp_list->quotas->usedspace;
- info.quota_threshold = tmp_list->quotas->softlim;
- info.quota_limit = tmp_list->quotas->hardlim;
-
- err = ndr_push_file_quota_information(header_ndr,
- ndr_flags,
- &info);
-
- if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
- DBG_DEBUG("Failed to pull the quota sid\n");
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- /* pidl will align to 8 bytes due to 8 byte members*/
- next_align = header_ndr->offset;
- ndr_push_align(header_ndr, 8);
- next_align = header_ndr->offset - next_align;
- info.next_entry_offset = header_ndr->offset - start_offset;
-
- if (return_single) {
- break;
- }
-
- /* write nextentryoffset to the buffer too */
- SIVAL(header_ndr->data, start_offset, info.next_entry_offset);
- }
-
-
- qt_handle->tmp_list = tmp_list;
-
- *datalen = header_ndr->offset - next_align;
- *data = header_ndr->data;
-
- if (num_pushed) {
- /* terminate the list */
- SIVAL(header_ndr->data, start_offset, 0);
- }
-
- /*
- * if we failed to write a single file_quota_information
- * issue BUFFER_TOO_SMALL
- */
- if (max_data_exceeded && num_pushed < 1) {
- return NT_STATUS_BUFFER_TOO_SMALL;
- }
-
- return NT_STATUS_OK;
-}
-
NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
files_struct *fsp,
struct smb2_query_quota_info *info,
@@ -2563,8 +2464,8 @@ NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
{
NTSTATUS status;
SMB_NTQUOTA_HANDLE *qt_handle = NULL;
- uint8_t *data = NULL;
- uint32_t data_size = 0;
+ SMB_NTQUOTA_LIST *qt_list = NULL;
+ DATA_BLOB blob = data_blob_null;
enum ndr_err_code err;
DBG_DEBUG("sidlistlength = %d, startsidlength = %d, "
@@ -2649,14 +2550,18 @@ NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx,
}
}
- status = fill_quota_buffer(mem_ctx, qt_handle,
- info->restart_scan !=0,
+ if (info->restart_scan !=0 ) {
+ qt_list = qt_handle->quota_list;
+ } else {
+ qt_list = qt_handle->tmp_list;
+ }
+ status = fill_quota_buffer(mem_ctx, qt_list,
info->return_single != 0,
max_data_count,
- &data,
- &data_size);
- *p_data = data;
- *p_data_size = data_size;
+ &blob,
+ &qt_handle->tmp_list);
+ *p_data = blob.data;
+ *p_data_size = blob.length;
done:
return status;
}
--
2.10.2
More information about the samba-technical
mailing list