The Samba-Bugzilla – Attachment 14382 Details for
Bug 13553
quotas don't work with SMB2
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
backport of patch to 4.9
quota-bits-4.9.patch (text/plain), 78.86 KB, created by
Noel Power
on 2018-08-01 10:32:29 UTC
(
hide
)
Description:
backport of patch to 4.9
Filename:
MIME Type:
Creator:
Noel Power
Created:
2018-08-01 10:32:29 UTC
Size:
78.86 KB
patch
obsolete
>From 2bfb9b4081fff1ef816bbfdd3ebb989d1c56ec1b Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Wed, 22 Mar 2017 14:53:22 +0000 >Subject: [PATCH 01/12] s3/lib: Fix misleading typo in debug message > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/lib/sysquotas.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/lib/sysquotas.c b/source3/lib/sysquotas.c >index eef87beafe0..9b2d37b8375 100644 >--- a/source3/lib/sysquotas.c >+++ b/source3/lib/sysquotas.c >@@ -418,7 +418,7 @@ static int command_set_quota(const char *path, enum SMB_QUOTA_TYPE qtype, unid_t > return -1; > } > >- DEBUG (3, ("get_quota: Running command %s\n", syscmd)); >+ DBG_NOTICE("set_quota: Running command %s\n", syscmd); > > lines = file_lines_pload(talloc_tos(), syscmd, NULL); > SAFE_FREE(syscmd); >-- >2.13.7 > > >From b93408246252fe1e3a72de33bcaa8ebb5fe7a1d2 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Tue, 28 Feb 2017 15:04:16 +0000 >Subject: [PATCH 02/12] 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. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > 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 4b9871c54df..3546ae422ec 100644 >--- a/source3/libsmb/cli_smb2_fnum.c >+++ b/source3/libsmb/cli_smb2_fnum.c >@@ -3047,6 +3047,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.13.7 > > >From 1033dd9e303fc91b97e2054713b714ed5f356eb8 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Tue, 28 Feb 2017 11:36:47 +0000 >Subject: [PATCH 03/12] 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. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > 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 b4a481fbf86..0ec20fe6337 100644 >--- a/source3/smbd/trans2.c >+++ b/source3/smbd/trans2.c >@@ -3475,7 +3475,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.13.7 > > >From fd7c6f9bc7eb2de565ae9dc0aae6932904d53ec9 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Thu, 2 Mar 2017 09:20:24 +0000 >Subject: [PATCH 04/12] librpc/idl Add some query [getset]info quota related > structures > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > 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 00000000000..7c4d00acfcb >--- /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 75eba7d54a5..f1588cd18fb 100644 >--- a/librpc/idl/wscript_build >+++ b/librpc/idl/wscript_build >@@ -38,6 +38,7 @@ bld.SAMBA_PIDL_LIST('PIDL', > fsrvp_state.idl > cab.idl > nfs4acl.idl >+ quota.idl > ''', > options='--header --ndr-parser', > output_dir='../gen_ndr') >diff --git a/librpc/wscript_build b/librpc/wscript_build >index 36414fbddf4..824c0f9828e 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.13.7 > > >From 07e9113291213831f489aac7cffe3ee99dfb3cea Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Fri, 26 May 2017 15:01:17 +0100 >Subject: [PATCH 05/12] s3/libsmb: adjust smb1 cli code to use idl structs and > ndr push/pull funcs. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/libsmb/cliquota.c | 397 +++++++++++++++++++++++++--------------------- > source3/libsmb/proto.h | 6 + > source3/wscript_build | 1 + > 3 files changed, 224 insertions(+), 180 deletions(-) > >diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c >index e22ccdd1931..7e8565b44b1 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,39 @@ 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; >- } >+ struct file_quota_information info = {0}; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ DATA_BLOB blob; >+ enum ndr_err_code err; >+ bool result = false; > >- /* offset to next quota record. >- * 4 bytes IVAL(rdata,0) >- * unused here... >- */ >- *offset = IVAL(rdata,0); >+ 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); > >- /* sid len */ >- sid_len = IVAL(rdata,4); >- if (40 + sid_len < 40) { >- return false; >+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) { >+ goto out; > } > >- if (rdata_count < 40+sid_len) { >- return False; >- } >+ *offset = info.next_entry_offset; > >- if (*offset != 0 && *offset < 40 + sid_len) { >- return false; >- } >+ ZERO_STRUCTP(pqt); >+ pqt->usedspace = info.quota_used; > >- /* unknown 8 bytes in pdata >- * maybe its the change time in NTTIME >- */ >+ pqt->softlim = info.quota_threshold; > >- /* the used space 8 bytes (uint64_t)*/ >- qt.usedspace = BVAL(rdata,16); >+ pqt->hardlim = info.quota_limit; > >- /* the soft quotas 8 bytes (uint64_t)*/ >- qt.softlim = BVAL(rdata,24); >- >- /* the hard quotas 8 bytes (uint64_t)*/ >- qt.hardlim = BVAL(rdata,32); >- >- if (!sid_parse(rdata+40,sid_len,&qt.sid)) { >- return false; >- } >- >- qt.qtype = SMB_USER_QUOTA_TYPE; >- >- *pqt = qt; >- >- 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, >@@ -217,111 +196,12 @@ 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; >- >- 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; >+ return fill_quota_buffer(mem_ctx, >+ qt_list, >+ false, >+ maxlen, >+ outbuf, >+ end_ptr); > } > > NTSTATUS build_fs_quota_buffer(TALLOC_CTX *mem_ctx, >@@ -367,43 +247,73 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, > SMB_NTQUOTA_STRUCT *pqt) > { > uint16_t setup[1]; >- uint8_t params[16]; >- unsigned int data_len; >- uint8_t data[SID_MAX_SIZE+8]; >- uint8_t *rparam, *rdata; >+ uint8_t *rparam = NULL, *rdata = NULL; > uint32_t rparam_count, rdata_count; > unsigned int sid_len; > unsigned int offset; >+ struct nttrans_query_quota_params get_quota = {0}; >+ struct file_get_quota_info info = {0}; >+ enum ndr_err_code err; >+ struct ndr_push *ndr_push = NULL; > NTSTATUS status; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ DATA_BLOB data_blob = data_blob_null; > > if (!cli||!pqt) { > smb_panic("cli_get_user_quota() called with NULL Pointer!"); > } > > if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { >+ TALLOC_FREE(frame); > return cli_smb2_get_user_quota(cli, quota_fnum, pqt); > } > >- SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA); >- >- SSVAL(params, 0,quota_fnum); >- SSVAL(params, 2,TRANSACT_GET_USER_QUOTA_FOR_SID); >- SIVAL(params, 4,0x00000024); >- SIVAL(params, 8,0x00000000); >- SIVAL(params,12,0x00000024); >+ get_quota.fid = quota_fnum; >+ get_quota.return_single_entry = 1; >+ get_quota.restart_scan = 0; > > sid_len = ndr_size_dom_sid(&pqt->sid, 0); >- data_len = sid_len+8; >- SIVAL(data, 0, 0x00000000); >- SIVAL(data, 4, sid_len); >- sid_linearize(data+8, sid_len, &pqt->sid); >+ >+ info.next_entry_offset = 0; >+ info.sid_length = sid_len; >+ info.sid = pqt->sid; >+ >+ err = ndr_push_struct_blob( >+ &data_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 out; >+ } >+ >+ get_quota.sid_list_length = data_blob.length; >+ get_quota.start_sid_offset = data_blob.length; >+ >+ ndr_push = ndr_push_init_ctx(frame); >+ >+ if (!ndr_push) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ >+ err = ndr_push_nttrans_query_quota_params(ndr_push, >+ NDR_SCALARS | NDR_BUFFERS, >+ &get_quota); >+ >+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) { >+ status = NT_STATUS_INTERNAL_ERROR; >+ goto out; >+ } > > 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 */ >- data, data_len, 112, /* data */ >+ ndr_push->data, ndr_push->offset, 4, /* params */ >+ data_blob.data, data_blob.length, 112, /* data */ > NULL, /* recv_flags2 */ > NULL, 0, NULL, /* rsetup */ > &rparam, 4, &rparam_count, >@@ -411,7 +321,7 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, > if (!NT_STATUS_IS_OK(status)) { > DEBUG(1, ("NT_TRANSACT_GET_USER_QUOTA failed: %s\n", > nt_errstr(status))); >- return status; >+ goto out; > } > > if (!parse_user_quota_record(rdata, rdata_count, &offset, pqt)) { >@@ -419,8 +329,10 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, > DEBUG(0,("Got INVALID NT_TRANSACT_GET_USER_QUOTA reply.\n")); > } > >+out: > TALLOC_FREE(rparam); > TALLOC_FREE(rdata); >+ TALLOC_FREE(frame); > return status; > } > >@@ -442,7 +354,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); >@@ -477,31 +397,42 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli, > bool first) > { > uint16_t setup[1]; >- uint8_t params[16]; >+ DATA_BLOB params_blob = data_blob_null; > uint8_t *rparam=NULL, *rdata=NULL; > uint32_t rparam_count=0, rdata_count=0; > NTSTATUS status; >- uint16_t op = first ? TRANSACT_GET_USER_QUOTA_LIST_START >- : TRANSACT_GET_USER_QUOTA_LIST_CONTINUE; >+ struct nttrans_query_quota_params quota_params = {0}; >+ enum ndr_err_code err; > >+ TALLOC_CTX *frame = NULL; > if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { > return cli_smb2_list_user_quota_step(cli, mem_ctx, quota_fnum, > pqt_list, first); > } >+ frame = talloc_stackframe(); > > SSVAL(setup + 0, 0, NT_TRANSACT_GET_USER_QUOTA); > >- SSVAL(params, 0,quota_fnum); >- SSVAL(params, 2, op); >- SIVAL(params, 4,0x00000000); >- SIVAL(params, 8,0x00000000); >- SIVAL(params,12,0x00000000); >+ quota_params.fid = quota_fnum; >+ if (first) { >+ quota_params.restart_scan = 1; >+ } >+ err = ndr_push_struct_blob( >+ ¶ms_blob, >+ frame, >+ "a_params, >+ (ndr_push_flags_fn_t)ndr_push_nttrans_query_quota_params); >+ >+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto cleanup; >+ } > > 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 */ >+ params_blob.data, params_blob.length, 4, /* params */ > NULL, 0, 2048, /* data */ > NULL, /* recv_flags2 */ > NULL, 0, NULL, /* rsetup */ >@@ -524,6 +455,7 @@ static NTSTATUS cli_list_user_quota_step(struct cli_state *cli, > cleanup: > TALLOC_FREE(rparam); > TALLOC_FREE(rdata); >+ TALLOC_FREE(frame); > > return status; > } >@@ -651,3 +583,108 @@ NTSTATUS cli_set_fs_quota_info(struct cli_state *cli, int quota_fnum, > > return status; > } >+ >+NTSTATUS fill_quota_buffer(TALLOC_CTX *mem_ctx, >+ SMB_NTQUOTA_LIST *qlist, >+ 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 *qndr = ndr_push_init_ctx(mem_ctx); >+ uint32_t start_offset = 0; >+ uint32_t padding = 0; >+ if (qlist == NULL) { >+ /* We must push at least one. */ >+ return NT_STATUS_NO_MORE_ENTRIES; >+ } >+ for (;qlist != NULL; qlist = qlist->next) { >+ struct file_quota_information info = {0}; >+ enum ndr_err_code err; >+ uint32_t dsize = 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 = ndr_size_dom_sid(&qlist->quotas->sid, 0); >+ >+ if (max_data) { >+ uint32_t curr_pos_no_padding = qndr->offset - padding; >+ uint32_t payload = dsize + info.sid_length; >+ uint32_t new_pos = (curr_pos_no_padding + payload); >+ if (new_pos < curr_pos_no_padding) { >+ /* Detect unlikely integer wrap */ >+ DBG_ERR("Integer wrap while adjusting pos " >+ "0x%x by offset 0x%x\n", >+ curr_pos_no_padding, payload); >+ return NT_STATUS_INTERNAL_ERROR; >+ } >+ if (new_pos > max_data) { >+ DBG_WARNING("Max data will be exceeded " >+ "writing next query info. " >+ "cur_pos 0x%x, sid_length 0x%x, " >+ "dsize 0x%x, max_data 0x%x\n", >+ curr_pos_no_padding, >+ info.sid_length, >+ dsize, >+ max_data); >+ break; >+ } >+ } >+ >+ start_offset = qndr->offset; >+ info.sid = qlist->quotas->sid; >+ info.quota_used = qlist->quotas->usedspace; >+ info.quota_threshold = qlist->quotas->softlim; >+ info.quota_limit = qlist->quotas->hardlim; >+ >+ err = ndr_push_file_quota_information(qndr, >+ ndr_flags, >+ &info); >+ >+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) { >+ DBG_DEBUG("Failed to push the quota sid\n"); >+ return NT_STATUS_INTERNAL_ERROR; >+ } >+ >+ /* pidl will align to 8 bytes due to 8 byte members*/ >+ /* Remember how much align padding we've used. */ >+ padding = qndr->offset; >+ ndr_push_align(qndr, 8); >+ padding = qndr->offset - padding; >+ >+ /* >+ * Overwrite next_entry_offset for this entry now >+ * we know what it should be. We know we're using >+ * LIBNDR_FLAG_LITTLE_ENDIAN here so we can use >+ * SIVAL. >+ */ >+ info.next_entry_offset = qndr->offset - start_offset; >+ SIVAL(qndr->data, start_offset, info.next_entry_offset); >+ >+ if (return_single) { >+ break; >+ } >+ } >+ >+ if (end_ptr != NULL) { >+ *end_ptr = qlist; >+ } >+ >+ /* Remove the padding alignment on the last element pushed. */ >+ blob->length = qndr->offset - padding; >+ blob->data = qndr->data; >+ >+ /* >+ * Terminate the pushed array by setting next_entry_offset >+ * for the last element to zero. >+ */ >+ if (blob->length >= sizeof(uint32_t)) { >+ SIVAL(qndr->data, start_offset, 0); >+ } >+ return NT_STATUS_OK; >+} >diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h >index d82de56a238..2bd61b1d2c2 100644 >--- a/source3/libsmb/proto.h >+++ b/source3/libsmb/proto.h >@@ -974,6 +974,12 @@ NTSTATUS cli_readlink(struct cli_state *cli, const char *fname, > TALLOC_CTX *mem_ctx, char **psubstitute_name, > char **pprint_name, uint32_t *pflags); > >+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); > /* The following definitions come from libsmb/passchange.c */ > > NTSTATUS remote_password_change(const char *remote_machine, >diff --git a/source3/wscript_build b/source3/wscript_build >index b51082913d9..7e38b79c3e2 100644 >--- a/source3/wscript_build >+++ b/source3/wscript_build >@@ -469,6 +469,7 @@ bld.SAMBA3_LIBRARY('libsmb', > LIBTSOCKET > KRBCLIENT > NDR_IOCTL >+ NDR_QUOTA > cli_smb_common > util_cmdline > tevent >-- >2.13.7 > > >From dd21b4fcfef4a663c43cf8e8601da350cbb0cfd3 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Fri, 26 May 2017 15:50:18 +0100 >Subject: [PATCH 06/12] s3/libsmb: adjust smb2 code for new idl structs & > generated ndr push/pull funcs. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/libsmb/cli_smb2_fnum.c | 86 ++++++++++++++++++++++++++++-------------- > 1 file changed, 58 insertions(+), 28 deletions(-) > >diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c >index 3546ae422ec..3537932c0d0 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; >@@ -2910,12 +2911,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)) { > /* >@@ -2937,27 +2942,52 @@ 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; >+ } >+ >+ 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); >+ >+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) { >+ status = NT_STATUS_INTERNAL_ERROR; >+ goto fail; >+ } >+ 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 */ >@@ -3002,7 +3032,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)) { > /* >@@ -3022,20 +3053,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; > >- 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 */ >+ err = ndr_push_struct_blob( >+ &inbuf, >+ frame, >+ &info, >+ (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info); >+ >+ 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 */ >-- >2.13.7 > > >From b8802e271337e5cec4f13ad4f505ae1905e09ca7 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Fri, 26 May 2017 16:01:53 +0100 >Subject: [PATCH 07/12] s3/smbd: adjust smb1 server to use idl structs and > generated ndr push/pull funcs > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/libsmb/cliquota.c | 19 +- > source3/smbd/nttrans.c | 660 ++++++++++++++++++++++++++-------------------- > source3/smbd/proto.h | 14 + > 3 files changed, 402 insertions(+), 291 deletions(-) > >diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c >index 7e8565b44b1..8efd2bbe38a 100644 >--- a/source3/libsmb/cliquota.c >+++ b/source3/libsmb/cliquota.c >@@ -254,10 +254,10 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, > struct nttrans_query_quota_params get_quota = {0}; > struct file_get_quota_info info = {0}; > enum ndr_err_code err; >- struct ndr_push *ndr_push = NULL; > NTSTATUS status; > TALLOC_CTX *frame = talloc_stackframe(); > DATA_BLOB data_blob = data_blob_null; >+ DATA_BLOB param_blob = data_blob_null; > > if (!cli||!pqt) { > smb_panic("cli_get_user_quota() called with NULL Pointer!"); >@@ -292,16 +292,11 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, > get_quota.sid_list_length = data_blob.length; > get_quota.start_sid_offset = data_blob.length; > >- ndr_push = ndr_push_init_ctx(frame); >- >- if (!ndr_push) { >- status = NT_STATUS_NO_MEMORY; >- goto out; >- } >- >- err = ndr_push_nttrans_query_quota_params(ndr_push, >- NDR_SCALARS | NDR_BUFFERS, >- &get_quota); >+ err = ndr_push_struct_blob( >+ ¶m_blob, >+ frame, >+ &get_quota, >+ (ndr_push_flags_fn_t)ndr_push_nttrans_query_quota_params); > > if (!NDR_ERR_CODE_IS_SUCCESS(err)) { > status = NT_STATUS_INTERNAL_ERROR; >@@ -312,7 +307,7 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, > NULL, -1, /* name, fid */ > NT_TRANSACT_GET_USER_QUOTA, 0, > setup, 1, 0, /* setup */ >- ndr_push->data, ndr_push->offset, 4, /* params */ >+ param_blob.data, param_blob.length, 4, /* params */ > data_blob.data, data_blob.length, 112, /* data */ > NULL, /* recv_flags2 */ > NULL, 0, NULL, /* rsetup */ >diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c >index ca02dbcc3d9..6967e4e1b37 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; > >@@ -2293,285 +2295,391 @@ static void call_nt_transact_ioctl(connection_struct *conn, > > > #ifdef HAVE_SYS_QUOTAS >-/**************************************************************************** >- Reply to get user quota >-****************************************************************************/ >- >-static void call_nt_transact_get_user_quota(connection_struct *conn, >- struct smb_request *req, >- uint16_t **ppsetup, >- uint32_t setup_count, >- char **ppparams, >- uint32_t parameter_count, >- char **ppdata, >- uint32_t data_count, >- uint32_t max_data_count) >+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) > { >- 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; >- >- ZERO_STRUCT(qt); >- >- /* 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; >- } >+ int i; >+ TALLOC_CTX *list_ctx = NULL; > >- /* >- * Ensure minimum number of parameters sent. >- */ >+ list_ctx = talloc_init("quota_sid_list"); > >- 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; >+ if (list_ctx == NULL) { >+ DBG_ERR("failed to allocate\n"); >+ return NDR_ERR_ALLOC; > } > >- /* 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 (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; > >- /* 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; >- } >+ 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; >+ } > >- data_len = 0; >- SIVAL(params,0,data_len); > >- break; >- } >+ list_item = talloc_zero(list_ctx, SMB_NTQUOTA_LIST); >+ if (list_item == NULL) { >+ DBG_ERR("failed to allocate\n"); >+ return NDR_ERR_ALLOC; >+ } > >- start_enum = False; >+ 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; >+ } > >- FALL_THROUGH; >- case TRANSACT_GET_USER_QUOTA_LIST_START: >+ *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; >+} > >- if (qt_handle->quota_list==NULL && >- qt_handle->tmp_list==NULL) { >- start_enum = True; >- } >+static enum ndr_err_code extract_sids_from_buf(TALLOC_CTX *mem_ctx, >+ uint32_t sidlistlength, >+ 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; >+ } > >- if (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) { >- reply_nterror(req, NT_STATUS_INTERNAL_ERROR); >- return; >- } >+ *num = 0; >+ *sids = NULL; > >- /* 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); >+ if (sidlistlength) { >+ uint32_t offset = 0; >+ struct ndr_pull *ndr_pull = NULL; > >- 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; >+ if (sidlistlength > sid_buf->length) { >+ DBG_ERR("sid_list_length 0x%x exceeds " >+ "available bytes %zx\n", >+ sidlistlength, >+ sid_buf->length); >+ err = NDR_ERR_OFFSET; >+ goto done; >+ } >+ while (true) { >+ struct file_get_quota_info info; >+ struct sid_list_elem *item = NULL; >+ uint32_t new_offset = 0; >+ blob.data = sid_buf->data + offset; >+ blob.length = sidlistlength - offset; >+ ndr_pull = ndr_pull_init_blob(&blob, list_ctx); >+ if (!ndr_pull) { >+ DBG_ERR("OOM\n"); >+ err = NDR_ERR_ALLOC; >+ goto done; > } >- >- 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; >+ 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; > } >- >- 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); >- >- /* 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); >+ item = talloc_zero(list_ctx, struct sid_list_elem); >+ if (!item) { >+ DBG_ERR("OOM\n"); >+ err = NDR_ERR_ALLOC; >+ goto done; > } >- >- 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; >+ 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; > >- 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 new_offset == 0 no more sid(s) to read. */ >+ if (new_offset == 0) { >+ break; > } > >- 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; >+ /* Integer wrap? */ >+ if ((offset + new_offset) < offset) { >+ DBG_ERR("Integer wrap while adding " >+ "new_offset 0x%x to current " >+ "buffer offset 0x%x\n", >+ new_offset, offset); >+ err = NDR_ERR_OFFSET; >+ goto done; > } > >- 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; >- } >+ offset += new_offset; > >- if (!sid_parse((const uint8_t *)(pdata+8), sid_len, >- &sid)) { >- reply_nterror(req, NT_STATUS_INVALID_PARAMETER); >- return; >+ /* check if new offset is outside buffer boundry. */ >+ if (offset >= sidlistlength) { >+ DBG_ERR("bufsize 0x%x exceeded by " >+ "new offset 0x%x)\n", >+ sidlistlength, >+ offset); >+ err = NDR_ERR_OFFSET; >+ goto done; > } >+ } >+ *sids = talloc_zero_array(mem_ctx, struct dom_sid, i); >+ if (!sids) { >+ DBG_ERR("OOM\n"); >+ err = NDR_ERR_ALLOC; >+ goto done; >+ } > >- 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; >- } >+ *num = i; > >- /* 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; >- } >+ for (iter = sid_list, i = 0; iter; iter = iter->next, i++) { >+ (*sids)[i] = iter->sid; >+ DBG_DEBUG("quota SID[%u] %s\n", >+ (unsigned int)i, >+ sid_string_dbg(&iter->sid)); >+ } >+ } >+ err = NDR_ERR_SUCCESS; >+done: >+ TALLOC_FREE(list_ctx); >+ return err; >+} > >- pdata = nttrans_realloc(ppdata, data_len); >- if(pdata == NULL) { >- reply_nterror(req, NT_STATUS_NO_MEMORY); >- return; >- } >+NTSTATUS smbd_do_query_getinfo_quota(TALLOC_CTX *mem_ctx, >+ files_struct *fsp, >+ bool restart_scan, >+ bool return_single, >+ uint32_t sid_list_length, >+ 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; >+ SMB_NTQUOTA_LIST *qt_list = NULL; >+ DATA_BLOB blob = data_blob_null; >+ enum ndr_err_code err; > >- entry = pdata; >+ qt_handle = >+ (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data; > >- /* set params Size of returned Quota Data 4 bytes*/ >- SIVAL(params,0,data_len); >+ if (sid_list_length ) { >+ struct dom_sid *sids; >+ uint32_t elems = 0; >+ /* >+ * error check pulled offsets and lengths for wrap and >+ * exceeding available bytes. >+ */ >+ if (sid_list_length > sid_buf->length) { >+ DBG_ERR("sid_list_length 0x%x exceeds " >+ "available bytes %zx\n", >+ sid_list_length, >+ sid_buf->length); >+ return NT_STATUS_INVALID_PARAMETER; >+ } > >- /* nextoffset entry 4 bytes */ >- SIVAL(entry,0,0); >+ err = extract_sids_from_buf(mem_ctx, sid_list_length, >+ sid_buf, &sids, &elems); >+ if (!NDR_ERR_CODE_IS_SUCCESS(err) || elems == 0) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ err = fill_qtlist_from_sids(mem_ctx, >+ fsp, >+ qt_handle, >+ sids, >+ elems); >+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ } else if (restart_scan) { >+ if (vfs_get_user_ntquota_list(fsp, >+ &(qt_handle->quota_list))!=0) { >+ return NT_STATUS_INTERNAL_ERROR; >+ } >+ } else { >+ if (qt_handle->quota_list!=NULL && >+ qt_handle->tmp_list==NULL) { >+ free_ntquota_list(&(qt_handle->quota_list)); >+ } >+ } > >- /* then the len of the SID 4 bytes */ >- SIVAL(entry,4,sid_len); >+ if (restart_scan !=0 ) { >+ qt_list = qt_handle->quota_list; >+ } else { >+ qt_list = qt_handle->tmp_list; >+ } >+ status = fill_quota_buffer(mem_ctx, qt_list, >+ return_single != 0, >+ max_data_count, >+ &blob, >+ &qt_handle->tmp_list); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ if (blob.length > max_data_count) { >+ return NT_STATUS_BUFFER_TOO_SMALL; >+ } > >- /* unknown data 8 bytes uint64_t */ >- SBIG_UINT(entry,8,(uint64_t)0); /* this is not 0 in windows...-mezte*/ >+ *p_data = blob.data; >+ *p_data_size = blob.length; >+ return NT_STATUS_OK; >+} > >- /* the used disk space 8 bytes uint64_t */ >- SBIG_UINT(entry,16,qt.usedspace); >+/**************************************************************************** >+ Reply to get user quota >+****************************************************************************/ > >- /* the soft quotas 8 bytes uint64_t */ >- SBIG_UINT(entry,24,qt.softlim); >+static void call_nt_transact_get_user_quota(connection_struct *conn, >+ struct smb_request *req, >+ uint16_t **ppsetup, >+ uint32_t setup_count, >+ char **ppparams, >+ uint32_t parameter_count, >+ char **ppdata, >+ uint32_t data_count, >+ uint32_t max_data_count) >+{ >+ NTSTATUS nt_status = NT_STATUS_OK; >+ char *params = *ppparams; >+ char *pdata = *ppdata; >+ int data_len = 0; >+ int param_len = 0; >+ files_struct *fsp = NULL; >+ DATA_BLOB blob = data_blob_null; >+ struct nttrans_query_quota_params info = {0}; >+ enum ndr_err_code err; >+ TALLOC_CTX *tmp_ctx = NULL; >+ uint32_t resp_len = 0; >+ uint8_t *resp_data = 0; > >- /* the hard quotas 8 bytes uint64_t */ >- SBIG_UINT(entry,32,qt.hardlim); >+ tmp_ctx = talloc_init("ntquota_list"); >+ if (!tmp_ctx) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ goto error; >+ } > >- /* and now the SID */ >- sid_linearize((uint8_t *)(entry+40), sid_len, &sid); >+ /* 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)); >+ nt_status = NT_STATUS_ACCESS_DENIED; >+ goto error; >+ } >+ >+ blob.data = (uint8_t*)params; >+ blob.length = parameter_count; >+ >+ err = ndr_pull_struct_blob(&blob, tmp_ctx, &info, >+ (ndr_pull_flags_fn_t)ndr_pull_nttrans_query_quota_params); >+ >+ 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 = %u, info.restart_scan = %u, " >+ "info.sid_list_length = %u, info.start_sid_length = %u, " >+ "info.start_sid_offset = %u\n", >+ (unsigned int)info.return_single_entry, >+ (unsigned int)info.restart_scan, >+ (unsigned int)info.sid_list_length, >+ (unsigned int)info.start_sid_length, >+ (unsigned int)info.start_sid_offset); >+ >+ /* set blob to point at data for further parsing */ >+ blob.data = (uint8_t*)pdata; >+ blob.length = data_count; >+ /* >+ * Although MS-SMB ref is ambiguous here, a microsoft client will >+ * only ever send a start sid (as part of a list) with >+ * sid_list_length & start_sid_offset both set to the actual list >+ * length. Note: Only a single result is returned in this case >+ * In the case where either start_sid_offset or start_sid_length >+ * are set alone or if both set (but have different values) then >+ * it seems windows will return a number of entries from the start >+ * of the list of users with quotas set. This behaviour is undocumented >+ * and windows clients do not send messages of that type. As such we >+ * currently will reject these requests. >+ */ >+ if (info.start_sid_length >+ || (info.sid_list_length != info.start_sid_offset)) { >+ DBG_ERR("TRANSACT_GET_USER_QUOTA: unsupported single or " >+ "compound sid format\n"); >+ nt_status = NT_STATUS_INVALID_PARAMETER; >+ goto error; >+ } > >- break; >+ /* 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.restart_scan, >+ info.return_single_entry, >+ info.sid_list_length, >+ &blob, >+ max_data_count, >+ &resp_data, >+ &resp_len); >+ if (!NT_STATUS_IS_OK(nt_status)) { >+ if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MORE_ENTRIES)) { >+ goto error; >+ } >+ nt_status = NT_STATUS_OK; >+ } > >- 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; >+ param_len = 4; >+ params = nttrans_realloc(ppparams, param_len); >+ if(params == NULL) { >+ nt_status = NT_STATUS_NO_MEMORY; >+ goto error; > } > >+ data_len = resp_len; >+ SIVAL(params, 0, data_len); >+ pdata = nttrans_realloc(ppdata, data_len); >+ 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); > } > > /**************************************************************************** >@@ -2592,10 +2700,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 */ >@@ -2603,8 +2714,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; > } > > /* >@@ -2613,67 +2724,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... >- */ >- >- /* sid len */ >- sid_len = IVAL(pdata,4); >+ err = ndr_pull_struct_blob( >+ &inblob, >+ ctx, >+ &info, >+ (ndr_pull_flags_fn_t)ndr_pull_file_quota_information); > >- 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 >- */ >- >- /* the used space 8 bytes (uint64_t)*/ >- qt.usedspace = BVAL(pdata,16); >- >- /* the soft quotas 8 bytes (uint64_t)*/ >- qt.softlim = BVAL(pdata,24); >- >- /* the hard quotas 8 bytes (uint64_t)*/ >- qt.hardlim = BVAL(pdata,32); >+ qt.softlim = info.quota_threshold; > >- if (!sid_parse((const uint8_t *)(pdata+40), sid_len, &sid)) { >- reply_nterror(req, NT_STATUS_INVALID_PARAMETER); >- return; >- } >+ qt.hardlim = info.quota_limit; > >- 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 */ > >diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h >index 2980935e599..2a41d9d251d 100644 >--- a/source3/smbd/proto.h >+++ b/source3/smbd/proto.h >@@ -640,6 +640,20 @@ 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, >+ bool restart_scan, >+ bool return_single, >+ uint32_t sid_list_length, >+ 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); > >-- >2.13.7 > > >From 907038417673dc0076838586e620b88513d78cb0 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Fri, 26 May 2017 16:02:33 +0100 >Subject: [PATCH 08/12] s3/smbd: smb2 server implementation for query get/set > info. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_getinfo.c | 86 +++++++++++++++++++++++++++++++++++++++++++-- > source3/smbd/smb2_setinfo.c | 36 +++++++++++++++++++ > source3/wscript_build | 1 + > 3 files changed, 120 insertions(+), 3 deletions(-) > >diff --git a/source3/smbd/smb2_getinfo.c b/source3/smbd/smb2_getinfo.c >index da82bf52378..05c57db902d 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" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_SMB2 >@@ -520,9 +522,87 @@ 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; >+ DATA_BLOB sid_buf = data_blob_null; >+ TALLOC_CTX *tmp_ctx = talloc_init("geninfo_quota"); >+ >+ 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) { >+ TALLOC_FREE(tmp_ctx); >+ 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"); >+ TALLOC_FREE(tmp_ctx); >+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); >+ return tevent_req_post(req, ev); >+ } >+ >+ DBG_DEBUG("quota list returnsingle %u, restartscan %u, " >+ "sid_list_length %u, start_sid_length %u, " >+ "startsidoffset %u\n", >+ (unsigned int)info.return_single, >+ (unsigned int)info.restart_scan, >+ (unsigned int)info.sid_list_length, >+ (unsigned int)info.start_sid_length, >+ (unsigned int)info.start_sid_offset); >+ >+ /* Currently we do not support the single start sid format */ >+ if (info.start_sid_length != 0 || info.start_sid_offset != 0 ) { >+ DBG_INFO("illegal single sid query\n"); >+ TALLOC_FREE(tmp_ctx); >+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); >+ return tevent_req_post(req, ev); >+ } >+ >+ if (in_input_buffer.length < ndr_pull->offset) { >+ DBG_INFO("Invalid buffer length\n"); >+ TALLOC_FREE(tmp_ctx); >+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); >+ return tevent_req_post(req, ev); >+ } >+ >+ 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.restart_scan, >+ info.return_single, >+ info.sid_list_length, >+ &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/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c >index 1f07b7e1190..7ed24231a83 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" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_SMB2 >@@ -553,6 +554,41 @@ 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; >+ int ret; >+ >+ 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; >+ ret = vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &qt.sid, &qt); >+ if (ret !=0 ) { >+ status = map_nt_error_from_unix(errno); >+ tevent_req_nterror(req, status); >+ 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); >diff --git a/source3/wscript_build b/source3/wscript_build >index 7e38b79c3e2..6e34bfaecf0 100644 >--- a/source3/wscript_build >+++ b/source3/wscript_build >@@ -740,6 +740,7 @@ bld.SAMBA3_LIBRARY('smbd_base', > NDR_IOCTL > notifyd > vfs_acl_common >+ NDR_QUOTA > ''' + > bld.env['dmapi_lib'] + > bld.env['legacy_quota_libs'] + >-- >2.13.7 > > >From 90da2e599b1e46beea1d3dc4b6e9338786250882 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Wed, 8 Mar 2017 14:27:27 +0000 >Subject: [PATCH 09/12] s3/script/test: modify existing smbcquota test to use > SMB2 in addition to SMB1. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > 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 abd82b46751..444a6684942 100755 >--- a/source3/script/tests/test_dfree_quota.sh >+++ b/source3/script/tests/test_dfree_quota.sh >@@ -164,13 +164,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}") >@@ -191,7 +199,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` > > # Test dfree cache through queries in two different directories > test_smbclient_dfree_2 "Test dfree cache" dfq_cache "." "subdir1" \ >-- >2.13.7 > > >From 801c1856a39cbc2fd65183a7d6d8b7526dbc251e Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Tue, 21 Mar 2017 08:29:59 +0000 >Subject: [PATCH 10/12] s3/script/tests: Add simple (smb1 & smb2) get/set/list > tests for smbcquotas > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > selftest/target/Samba3.pm | 9 ++ > source3/script/tests/getset_quota.py | 154 +++++++++++++++++++++ > source3/script/tests/test_smbcquota.py | 244 +++++++++++++++++++++++++++++++++ > source3/script/tests/test_smbcquota.sh | 46 +++++++ > source3/selftest/tests.py | 1 + > 5 files changed, 454 insertions(+) > create mode 100755 source3/script/tests/getset_quota.py > create mode 100755 source3/script/tests/test_smbcquota.py > create mode 100755 source3/script/tests/test_smbcquota.sh > >diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm >index 5b8cf9ea6d8..447c1e8e3a7 100755 >--- a/selftest/target/Samba3.pm >+++ b/selftest/target/Samba3.pm >@@ -885,6 +885,9 @@ sub setup_fileserver > push(@dirs, "$dfree_share_dir/subdir2"); > push(@dirs, "$dfree_share_dir/subdir3"); > >+ my $quotadir_dir="$share_dir/quota"; >+ push(@dirs, $quotadir_dir); >+ > my $valid_users_sharedir="$share_dir/valid_users"; > push(@dirs,$valid_users_sharedir); > >@@ -911,6 +914,8 @@ sub setup_fileserver > usershare allow guests = yes > usershare prefix allow list = $usershare_sharedir > >+ get quota command = $prefix_abs/getset_quota.py >+ set quota command = $prefix_abs/getset_quota.py > [lowercase] > path = $lower_case_share_dir > comment = smb username is [%U] >@@ -2170,6 +2175,10 @@ sub provision($$$$$$$$$) > vfs objects = acl_xattr fake_acls xattr_tdb fake_dfq > inherit owner = yes > include = $dfqconffile >+[quotadir] >+ path = $shrdir/quota >+ admin users = $unix_name >+ > [acl_xattr_ign_sysacl_posix] > copy = tmp > acl_xattr:ignore system acls = yes >diff --git a/source3/script/tests/getset_quota.py b/source3/script/tests/getset_quota.py >new file mode 100755 >index 00000000000..0254aa5a3b3 >--- /dev/null >+++ b/source3/script/tests/getset_quota.py >@@ -0,0 +1,154 @@ >+#!/usr/bin/env python3 >+# Unix SMB/CIFS implementation. >+# Tests for smbcquotas >+# Copyright (C) Noel Power 2017 >+ >+# This program is free software; you can redistribute it and/or modify >+# it under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+ >+# This program is distributed in the hope that it will be useful, >+# but WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+ >+# You should have received a copy of the GNU General Public License >+# along with this program. If not, see <http://www.gnu.org/licenses/>. >+ >+import sys >+import traceback >+import logging >+import os >+ >+USER_QUOTAS = 1 >+USER_DEFAULT_QUOTAS = 2 >+GROUP_QUOTAS = 3 >+GROUP_DEFAULT_QUOTAS = 4 >+ >+#Quota model >+ >+class Quota: >+ def __init__(self): >+ self.flags = 0 >+ self.quotatype = USER_DEFAULT_QUOTAS >+ self.uid = 0 >+ self.usedblocks = 0 >+ self.softlimit = 0 >+ self.hardlimit = 0 >+ self.hardlimit = 0 >+ self.usedinodes = 0 >+ self.slimitinodes = 0 >+ self.hlimitinodes = 0 >+ >+def quota_to_str(item): >+ result = str(item.flags) + " " + str(item.usedblocks) + " " + str(item.softlimit) + " " + str(item.hardlimit) + " " + str(item.usedinodes) + " " + str(item.slimitinodes) + " " + str(item.hlimitinodes) >+ return result >+ >+def quota_to_db_str(item): >+ result = item.uid + " " + str(item.usedblocks) + " " + str(item.softlimit) + " " + str(item.hardlimit) + " " + str(item.usedinodes) + " " + str(item.slimitinodes) + " " + str(item.hlimitinodes) >+ return result >+ >+def load_quotas(input_file): >+ fileContents = open(input_file,"r") >+ lineno = 0 >+ quotas = [] >+ for line in fileContents: >+ if line.strip().startswith("#"): >+ continue >+ content = line.strip().split() >+ quota = Quota() >+ if len(content) < 7: >+ logging.debug("ignoring line %d, doesn't have enough fields\n"%lineno) >+ else: >+ quota.flags = 2 >+ quota.uid = content[0] >+ quota.usedblocks = content[1] >+ quota.softlimit = content[2] >+ quota.hardlimit = content[3] >+ quota.usedinodes = content[4] >+ quota.slimitinodes = content[5] >+ quota.hlimitinodes = content[6] >+ quotas.append(quota) >+ >+ fileContents.close() >+ return quotas >+ >+def set_quotas(quota_list, output_file): >+ filecontents = open(output_file,"w+") >+ if filecontents == None: >+ return False; >+ lines = "" >+ for quota in quota_list: >+ next_line = quota_to_db_str(quota) >+ if next_line: >+ lines = lines + next_line + "\n" >+ filecontents.write(lines) >+ filecontents.close() >+ return True >+ >+def get_quotas(uid, quota_list): >+ logging.debug("in get_quotas\n") >+ for quota in quota_list: >+ if quota.uid == uid: >+ return quota >+ return None >+ >+def main(): >+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG) >+ logging.debug("system args passed are %s\n"% str(sys.argv)) >+ quota_file_dir = os.path.dirname(sys.argv[0]); >+ quota_file_db = os.path.join(quota_file_dir,"quotas.db") >+ logging.debug("quota db is located %s\n", quota_file_db) >+ quota_list = load_quotas(quota_file_db) >+ logging.debug("quotas loaded have %s entries\n", len(quota_list)) >+ result = None >+ if len(sys.argv) == 4: >+ # Get Quota >+ directory = sys.argv[1] >+ if sys.argv[2] == "1": >+ query_type = USER_QUOTAS >+ elif sys.argv[2] == "2": >+ query_type = USER_DEFAULT_QUOTAS >+ elif sys.argv[2] == "3": >+ query_type = GROUP_QUOTAS >+ elif sys.argv[2] == "4": >+ query_type = GROUP_DEFAULT_QUOTAS >+ uid = sys.argv[3] >+ quota = get_quotas(uid, quota_list) >+ if quota is None: >+ logging.debug("no result for uid %s"%uid) >+ else: >+ result = quota_to_str(quota) >+ logging.debug("got result for uid %s\n"%uid); >+ if result is None: >+ result = "0 0 0 0 0 0 0" >+ logging.debug("for uid %s returning quotas %s\n"%(uid,result)) >+ print("%s"%result) >+ elif len(sys.argv) > 8: >+ # Set Quota >+ quota = Quota() >+ directory = sys.argv[1] >+ quota.query_type = sys.argv[2] >+ quota.uid = sys.argv[3] >+ quota.flags = sys.argv[4] >+ quota.softlimit = sys.argv[5] >+ quota.hardlimit = sys.argv[6] >+ quota.slimitinodes = sys.argv[7] >+ quota.hlimitinodes = sys.argv[8] >+ found = get_quotas(quota.uid, quota_list) >+ if found: >+ found.query_type = quota.query_type >+ found.uid = quota.uid >+ found.flags = quota.flags >+ found.softlimit = quota.softlimit >+ found.hardlimit = quota.hardlimit >+ found.slimitinodes = quota.slimitinodes >+ found.hlimitinodes = quota.hlimitinodes >+ else: >+ quota_list.append(quota) >+ if set_quotas(quota_list,quota_file_db): >+ print ("%s\n"%quota_to_str(quota_list[-1])) >+ return >+if __name__ == '__main__': >+ main() >diff --git a/source3/script/tests/test_smbcquota.py b/source3/script/tests/test_smbcquota.py >new file mode 100755 >index 00000000000..52061f2989f >--- /dev/null >+++ b/source3/script/tests/test_smbcquota.py >@@ -0,0 +1,244 @@ >+#!/usr/bin/env python3 >+# Unix SMB/CIFS implementation. >+# Tests for smbcquotas >+# Copyright (C) Noel Power 2017 >+ >+# This program is free software; you can redistribute it and/or modify >+# it under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+ >+# This program is distributed in the hope that it will be useful, >+# but WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+ >+# You should have received a copy of the GNU General Public License >+# along with this program. If not, see <http://www.gnu.org/licenses/>. >+ >+import os, subprocess, sys >+import traceback >+import logging >+import shutil >+ >+USER_QUOTAS = 1 >+USER_DEFAULT_QUOTAS = 2 >+GROUP_QUOTAS = 3 >+GROUP_DEFAULT_QUOTAS = 4 >+BLOCK_SIZE = 1024 >+DEFAULT_SOFTLIM = 2 >+DEFAULT_HARDLIM = 4 >+ >+class test_env: >+ def __init__(self): >+ self.server = None >+ self.domain = None >+ self.username = None >+ self.password = None >+ self.envdir = None >+ self.quota_db = None >+ self.smbcquotas = None >+ self.users = [] >+ >+class user_info: >+ def __init__(self): >+ self.uid = 0 >+ self.username = "" >+ self.softlim = 0 >+ self.hardlim = 0 >+ >+class Quota: >+ def __init__(self): >+ self.flags = 0 >+ self.quotatype = USER_DEFAULT_QUOTAS >+ self.uid = 0 >+ self.usedblocks = 0 >+ self.softlimit = 0 >+ self.hardlimit = 0 >+ self.hardlimit = 0 >+ self.usedinodes = 0 >+ self.slimitinodes = 0 >+ self.hlimitinodes = 0 >+ >+def init_quota_db(users, output_file): >+ filecontents = open(output_file,"w+") >+ lines = "" >+ default_values = "0 " + str(DEFAULT_SOFTLIM) + " " + str(DEFAULT_HARDLIM) + " 0 0 0" >+ for user in users: >+ lines = lines + user.uid + " " + default_values + "\n" >+ filecontents.write(lines) >+ filecontents.close() >+ >+def load_quotas(input_file): >+ fileContents = open(input_file,"r") >+ lineno = 0 >+ quotas = [] >+ for line in fileContents: >+ if line.strip().startswith("#"): >+ continue >+ content = line.strip().split() >+ quota = Quota() >+ if len(content) < 7: >+ logging.debug("ignoring line %d, doesn't have enough fields\n"%lineno) >+ else: >+ quota.flags = 2 >+ quota.uid = content[0] >+ quota.usedblocks = content[1] >+ quota.softlimit = content[2] >+ quota.hardlimit = content[3] >+ quota.usedinodes = content[4] >+ quota.slimitinodes = content[5] >+ quota.hlimitinodes = content[6] >+ quotas.append(quota) >+ >+ fileContents.close() >+ return quotas >+ >+def get_quotas(uid, quota_list): >+ for quota in quota_list: >+ if quota.uid == uid: >+ return quota >+ return None >+ >+def get_users(): >+ output = subprocess.Popen(['getent', 'passwd'], >+ stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n') >+ users = [] >+ for line in output: >+ info = line.split(':') >+ if len(info) > 3 and info[0]: >+ user = user_info() >+ user.username = info[0] >+ user.uid = info[2] >+ logging.debug("Adding user ->%s<-\n"%user.username) >+ users.append(user) >+ return users >+ >+ >+ >+def smbcquota_output_to_userinfo(output): >+ infos = [] >+ for line in output: >+ if len(line) > 1: >+ username = line.strip(':').split()[0] >+ quota_info = line.split(':')[1].split('/') >+ if len(quota_info) > 2: >+ info = user_info() >+ info.username = username.strip() >+ info.softlim = int(quota_info[1].strip()) / BLOCK_SIZE >+ info.hardlim = int(quota_info[2].strip()) / BLOCK_SIZE >+ infos.append(info) >+ return infos >+ >+def check_quota_limits(infos, softlim, hardlim): >+ if len(infos) < 1: >+ logging.debug("no users info to check :-(\n") >+ return False >+ for info in infos: >+ if int(info.softlim) != softlim: >+ logging.debug("expected softlimit %s got ->%s<-\n"%(softlim, info.softlim)) >+ return False >+ if int(info.hardlim) != hardlim: >+ logging.debug("expected hardlimit limit %s got %s\n"%(hardlim,info.hardlim)) >+ return False >+ return True >+ >+class test_base: >+ def __init__(self, env): >+ self.env = env >+ def run(self, protocol): >+ pass >+ >+class listtest(test_base): >+ def run(self, protocol): >+ init_quota_db(self.env.users, self.env.quota_db) >+ quotas = load_quotas(self.env.quota_db) >+ args = [self.env.smbcquotas]; >+ remaining_args = ['-U' + self.env.username + "%" + self.env.password, '-L', '//' + self.env.server + '/quotadir'] >+ if protocol == 'smb2': >+ args.append('-m smb2') >+ args.extend(remaining_args) >+ output = subprocess.Popen([self.env.smbcquotas, '-U' + self.env.username + "%" + self.env.password, '-L', '//' + self.env.server + '/quotadir'], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n') >+ infos = smbcquota_output_to_userinfo(output) >+ return check_quota_limits(infos, DEFAULT_SOFTLIM, DEFAULT_HARDLIM) >+def get_uid(name, users): >+ for user in users: >+ if user.username == name: >+ return user.uid >+ return None >+ >+class gettest(test_base): >+ def run(self, protocol): >+ init_quota_db(self.env.users, self.env.quota_db) >+ quotas = load_quotas(self.env.quota_db) >+ uid = get_uid(self.env.username, self.env.users) >+ output = subprocess.Popen([self.env.smbcquotas, '-U' + self.env.username + "%" + self.env.password, '-u' + self.env.username, '//' + self.env.server + '/quotadir'], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n') >+ user_infos = smbcquota_output_to_userinfo(output) >+ db_user_info = get_quotas(uid, quotas) >+ # double check, we compare the results from the db file >+ # the quota script the server uses compared to what >+ # smbcquota is telling us >+ return check_quota_limits(user_infos, int(db_user_info.softlimit), int(db_user_info.hardlimit)) >+ >+class settest(test_base): >+ def run(self, protocol): >+ init_quota_db(self.env.users, self.env.quota_db) >+ quotas = load_quotas(self.env.quota_db) >+ uid = get_uid(self.env.username, self.env.users) >+ old_db_user_info = get_quotas(uid, quotas) >+ >+ #increase limits by 2 blocks >+ new_soft_limit = (int(old_db_user_info.softlimit) + 2) * BLOCK_SIZE >+ new_hard_limit = (int(old_db_user_info.hardlimit) + 2) * BLOCK_SIZE >+ >+ new_limits = "UQLIM:%s:%d/%d"%(self.env.username, new_soft_limit, new_hard_limit) >+ logging.debug("setting new limits %s"%new_limits) >+ >+ output = subprocess.Popen([self.env.smbcquotas, '-U' + self.env.username + "%" + self.env.password, '//' + self.env.server + '/quotadir', '-S', new_limits], stdout=subprocess.PIPE).communicate()[0].decode("utf-8").split('\n') >+ logging.debug("output from smbcquota is %s"%output) >+ user_infos = smbcquota_output_to_userinfo(output) >+ return check_quota_limits(user_infos, new_soft_limit / BLOCK_SIZE, new_hard_limit / BLOCK_SIZE) >+ >+# map of tests >+subtest_descriptions = { >+ "list test" : listtest, >+ "get test" : gettest, >+ "set test" : settest >+} >+ >+def main(): >+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.DEBUG) >+ >+ logging.debug("got args %s\n"%str(sys.argv)) >+ >+ if len(sys.argv) < 7: >+ logging.debug ("Usage: test_smbcquota.py server domain username password envdir smbcquotas\n") >+ sys.exit(1) >+ env = test_env() >+ env.server = sys.argv[1] >+ env.domain = sys.argv[2] >+ env.username = sys.argv[3] >+ env.password = sys.argv[4] >+ env.envdir = sys.argv[5] >+ env.smbcquotas = sys.argv[6] >+ quota_script = os.path.join(os.path.dirname(sys.argv[0]), >+ "getset_quota.py") >+ #copy the quota script to the evironment >+ shutil.copy2(quota_script, env.envdir) >+ >+ env.quota_db = os.path.join(env.envdir, "quotas.db") >+ env.users = get_users() >+ for protocol in ['smb1', 'smb2']: >+ for key in subtest_descriptions.keys(): >+ test = subtest_descriptions[key](env) >+ logging.debug("running subtest '%s' using protocol '%s'\n"%(key,protocol)) >+ result = test.run(protocol) >+ if result == False: >+ logging.debug("subtest '%s' for '%s' failed\n"%(key,protocol)) >+ sys.exit(1) >+ else: >+ logging.debug("subtest '%s' for '%s' passed\n"%(key,protocol)) >+ sys.exit(0) >+ >+if __name__ == '__main__': >+ main() >diff --git a/source3/script/tests/test_smbcquota.sh b/source3/script/tests/test_smbcquota.sh >new file mode 100755 >index 00000000000..a61c2fe6d0b >--- /dev/null >+++ b/source3/script/tests/test_smbcquota.sh >@@ -0,0 +1,46 @@ >+#!/bin/sh >+# Unix SMB/CIFS implementation. >+# Tests for smbcquotas >+# Copyright (C) Noel Power 2017 >+ >+# This program is free software; you can redistribute it and/or modify >+# it under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+ >+# This program is distributed in the hope that it will be useful, >+# but WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+ >+# You should have received a copy of the GNU General Public License >+# along with this program. If not, see <http://www.gnu.org/licenses/>. >+# >+ >+# >+# Blackbox test wrapper for smbcquota >+# >+if [ $# -lt 6 ]; then >+cat <<EOF >+Usage: test_smbcquota.sh SERVER DOMAIN USERNAME PASSWORD LOCAL_PATH SMBCQUOTAS >+EOF >+exit 1; >+fi >+ >+SERVER=$1 >+DOMAIN=$2 >+USERNAME=$3 >+PASSWORD=$4 >+ENVDIR=`dirname $5` >+SMBCQUOTAS="$VALGRIND $6" >+shift 6 >+ >+TEST_SMBCQUOTAS=`dirname $0`/test_smbcquota.py >+ >+incdir=`dirname $0`/../../../testprogs/blackbox >+. $incdir/subunit.sh >+ >+ >+testit "smbcquotas" ${TEST_SMBCQUOTAS} ${SERVER} ${DOMAIN} ${USERNAME} ${PASSWORD} ${ENVDIR} ${SMBCQUOTAS} || failed=`expr $failed + 1` >+ >+testok $0 $failed >diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py >index b2b2ff26077..d3c54870377 100755 >--- a/source3/selftest/tests.py >+++ b/source3/selftest/tests.py >@@ -284,6 +284,7 @@ for env in ["fileserver"]: > plantestsuite("samba3.blackbox.preserve_case (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_preserve_case.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3]) > plantestsuite("samba3.blackbox.dfree_command (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_command.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3]) > plantestsuite("samba3.blackbox.dfree_quota (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_quota.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3, smbcquotas, smbcacls]) >+ plantestsuite("samba3.blackbox.smbcquotas (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_smbcquota.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbcquotas]) > plantestsuite("samba3.blackbox.valid_users (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_valid_users.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3]) > plantestsuite("samba3.blackbox.offline (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3]) > plantestsuite("samba3.blackbox.shadow_copy2 NT1 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'NT1']) >-- >2.13.7 > > >From 705086d83c847c707e8230ce6a58e840a70d93c3 Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Wed, 22 Mar 2017 20:06:13 +0000 >Subject: [PATCH 11/12] s3/smbd: allow set quota for non root user (when built > with --enable-selftest) > >Currently it appears you need to be root to set quotas, for test purposes >this requirement needs to be relaxed. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/nttrans.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c >index 6967e4e1b37..5937380fb85 100644 >--- a/source3/smbd/nttrans.c >+++ b/source3/smbd/nttrans.c >@@ -2710,7 +2710,7 @@ static void call_nt_transact_set_user_quota(connection_struct *conn, > ZERO_STRUCT(qt); > > /* access check */ >- if (get_current_uid(conn) != 0) { >+ if (get_current_uid(conn) != sec_initial_uid()) { > 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)); >-- >2.13.7 > > >From e053aad4ae46dfcda6143d55e8e913e923fa34be Mon Sep 17 00:00:00 2001 >From: Noel Power <noel.power@suse.com> >Date: Thu, 28 Jun 2018 16:04:24 +0100 >Subject: [PATCH 12/12] s3/utils: fix regression where specifying > -Unetbios/root works > >Usually you need to be root on a linux server to modify quotas. Even >with a linux server joined to a windows AD you could always log in as >local root with smbcquotas. However in recent builds this has changed. >This patch fixes this > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13553 > >Signed-off-by: Noel Power <noel.power@suse.com> >Reviewed-by: Jeremy Allison <jra@samba.org> > >Autobuild-User(master): Noel Power <npower@samba.org> >Autobuild-Date(master): Tue Jul 31 19:45:59 CEST 2018 on sn-devel-144 >--- > source3/utils/smbcquotas.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > >diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c >index 031862f52a1..798b8b6f177 100644 >--- a/source3/utils/smbcquotas.c >+++ b/source3/utils/smbcquotas.c >@@ -533,7 +533,8 @@ static struct cli_state *connect_one(const char *share) > share, "?????", > get_cmdline_auth_info_username( > popt_get_cmdline_auth_info()), >- lp_workgroup(), >+ get_cmdline_auth_info_domain( >+ popt_get_cmdline_auth_info()), > get_cmdline_auth_info_password( > popt_get_cmdline_auth_info()), > flags, >-- >2.13.7 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
jra
:
review+
Actions:
View
Attachments on
bug 13553
:
14381
| 14382 |
14398
|
14409
|
14410
|
14411
|
14412
|
14474