From 5e9b1f77add716168283b3557d0ddc0cf175b6d7 Mon Sep 17 00:00:00 2001 From: Uri Simchoni Date: Wed, 21 Sep 2016 18:37:40 +0300 Subject: [PATCH] cliquota: factor out building of FILE_QUOTA_INFORMATION Add a function to build a FILE_QUOTA_INFORMATION buffer out of a quota list, and a function that adds a record to a quota list. Some parameters of the new functions are unused by client code, but will be used by server code. Signed-off-by: Uri Simchoni Reviewed-by: Jeremy Allison --- source3/libsmb/cliquota.c | 190 ++++++++++++++++++++++++++++++------- source3/libsmb/proto.h | 13 ++- source3/utils/smbcquotas.c | 16 +++- 3 files changed, 180 insertions(+), 39 deletions(-) diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c index 9a80eef336c8..f11d9a28fb98 100644 --- a/source3/libsmb/cliquota.c +++ b/source3/libsmb/cliquota.c @@ -47,6 +47,29 @@ void free_ntquota_list(SMB_NTQUOTA_LIST **qt_list) return; } +bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx, + SMB_NTQUOTA_STRUCT *pqt, + SMB_NTQUOTA_LIST **pqt_list) +{ + SMB_NTQUOTA_LIST *tmp_list_ent; + + if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) == NULL) { + return false; + } + + if ((tmp_list_ent->quotas = talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) == + NULL) { + return false; + } + + *tmp_list_ent->quotas = *pqt; + tmp_list_ent->mem_ctx = mem_ctx; + + DLIST_ADD((*pqt_list), tmp_list_ent); + + return true; +} + bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count, unsigned int *offset, @@ -117,7 +140,6 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, NTSTATUS status = NT_STATUS_OK; unsigned offset; SMB_NTQUOTA_STRUCT qt; - SMB_NTQUOTA_LIST *tmp_list_ent; while (true) { ZERO_STRUCT(qt); @@ -128,23 +150,6 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, break; } - if ((tmp_list_ent = talloc_zero(mem_ctx, SMB_NTQUOTA_LIST)) == - NULL) { - status = NT_STATUS_NO_MEMORY; - break; - } - - if ((tmp_list_ent->quotas = - talloc_zero(mem_ctx, SMB_NTQUOTA_STRUCT)) == NULL) { - status = NT_STATUS_NO_MEMORY; - break; - } - - memcpy(tmp_list_ent->quotas, &qt, sizeof(qt)); - tmp_list_ent->mem_ctx = mem_ctx; - - DLIST_ADD((*pqt_list), tmp_list_ent); - if (offset > curdata_count) { DEBUG(1, ("out of bounds offset in quota record\n")); status = NT_STATUS_INVALID_NETWORK_RESPONSE; @@ -157,6 +162,11 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, break; } + if (!add_record_to_ntquota_list(mem_ctx, &qt, pqt_list)) { + status = NT_STATUS_NO_MEMORY; + break; + } + curdata += offset; curdata_count -= offset; @@ -201,6 +211,119 @@ NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, return NT_STATUS_OK; } +NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list, + uint32_t maxlen, + TALLOC_CTX *mem_ctx, + DATA_BLOB *outbuf, + SMB_NTQUOTA_LIST **end_ptr) +{ + uint32_t qt_len = 0; + uint8_t *entry; + uint32_t entry_len; + int sid_len; + SMB_NTQUOTA_LIST *qtl; + DATA_BLOB qbuf = data_blob_null; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + + if (qt_list == NULL) { + status = NT_STATUS_OK; + *outbuf = data_blob_null; + if (end_ptr) { + *end_ptr = NULL; + } + return NT_STATUS_OK; + } + + for (qtl = qt_list; qtl != NULL; qtl = qtl->next) { + + sid_len = ndr_size_dom_sid(&qtl->quotas->sid, 0); + if (47 + sid_len < 47) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + entry_len = 40 + sid_len; + entry_len = ((entry_len + 7) / 8) * 8; + + if (qt_len + entry_len < qt_len) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + qt_len += entry_len; + } + + if (maxlen > 0 && qt_len > maxlen) { + qt_len = maxlen; + } + + qbuf = data_blob_talloc_zero(mem_ctx, qt_len); + if (qbuf.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + for (qt_len = 0, entry = qbuf.data; qt_list != NULL; + qt_list = qt_list->next, qt_len += entry_len, entry += entry_len) { + + sid_len = ndr_size_dom_sid(&qt_list->quotas->sid, 0); + entry_len = 40 + sid_len; + entry_len = ((entry_len + 7) / 8) * 8; + + if (qt_len + entry_len > qbuf.length) { + /* check for not-enough room even for a single + * entry + */ + if (qt_len == 0) { + status = NT_STATUS_BUFFER_TOO_SMALL; + goto fail; + } + + break; + } + + /* nextoffset entry 4 bytes */ + SIVAL(entry, 0, entry_len); + + /* then the len of the SID 4 bytes */ + SIVAL(entry, 4, sid_len); + + /* NTTIME of last record change */ + SBIG_UINT(entry, 8, (uint64_t)0); + + /* the used disk space 8 bytes uint64_t */ + SBIG_UINT(entry, 16, qt_list->quotas->usedspace); + + /* the soft quotas 8 bytes uint64_t */ + SBIG_UINT(entry, 24, qt_list->quotas->softlim); + + /* the hard quotas 8 bytes uint64_t */ + SBIG_UINT(entry, 32, qt_list->quotas->hardlim); + + /* and now the SID */ + sid_linearize((uint8_t *)(entry + 40), sid_len, + &qt_list->quotas->sid); + } + + /* overwrite the offset of the last entry */ + SIVAL(entry - entry_len, 0, 0); + + /*potentially shrink the buffer if max was given + * and we haven't quite reached the max + */ + qbuf.length = qt_len; + *outbuf = qbuf; + qbuf = data_blob_null; + status = NT_STATUS_OK; + + if (end_ptr) { + *end_ptr = qt_list; + } + +fail: + data_blob_free(&qbuf); + + return status; +} + NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt) { @@ -262,40 +385,33 @@ NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, return status; } -NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum, - SMB_NTQUOTA_STRUCT *pqt) +NTSTATUS +cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST *qtl) { uint16_t setup[1]; uint8_t params[2]; - uint8_t data[112]; - unsigned int sid_len; - NTSTATUS status; - - memset(data,'\0',112); + DATA_BLOB data = data_blob_null; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - if (!cli||!pqt) { + if (!cli || !qtl) { smb_panic("cli_set_user_quota() called with NULL Pointer!"); } + status = build_user_quota_buffer(qtl, 0, talloc_tos(), &data, NULL); + if (!NT_STATUS_IS_OK(status)) { + goto cleanup; + } + SSVAL(setup + 0, 0, NT_TRANSACT_SET_USER_QUOTA); SSVAL(params,0,quota_fnum); - sid_len = ndr_size_dom_sid(&pqt->sid, 0); - SIVAL(data,0,0); - SIVAL(data,4,sid_len); - SBIG_UINT(data, 8,(uint64_t)0); - SBIG_UINT(data,16,pqt->usedspace); - SBIG_UINT(data,24,pqt->softlim); - SBIG_UINT(data,32,pqt->hardlim); - sid_linearize(data+40, sid_len, &pqt->sid); - status = cli_trans(talloc_tos(), cli, SMBnttrans, NULL, -1, /* name, fid */ NT_TRANSACT_SET_USER_QUOTA, 0, setup, 1, 0, /* setup */ params, 2, 0, /* params */ - data, 112, 0, /* data */ + data.data, data.length, 0, /* data */ NULL, /* recv_flags2 */ NULL, 0, NULL, /* rsetup */ NULL, 0, NULL, /* rparams */ @@ -306,6 +422,8 @@ NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum, nt_errstr(status))); } +cleanup: + data_blob_free(&data); return status; } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index eaa9c8e42df6..1372dee3cac3 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -766,6 +766,9 @@ bool parse_user_quota_record(const uint8_t *rdata, unsigned int rdata_count, unsigned int *offset, SMB_NTQUOTA_STRUCT *pqt); +bool add_record_to_ntquota_list(TALLOC_CTX *mem_ctx, + SMB_NTQUOTA_STRUCT *pqt, + SMB_NTQUOTA_LIST **pqt_list); NTSTATUS parse_user_quota_list(const uint8_t *curdata, uint32_t curdata_size, TALLOC_CTX *mem_ctx, @@ -773,10 +776,16 @@ NTSTATUS parse_user_quota_list(const uint8_t *curdata, NTSTATUS parse_fs_quota_buffer(const uint8_t *rdata, unsigned int rdata_count, SMB_NTQUOTA_STRUCT *pqt); +NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list, + uint32_t maxlen, + TALLOC_CTX *mem_ctx, + DATA_BLOB *outbuf, + SMB_NTQUOTA_LIST **end_ptr); NTSTATUS cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUCT *pqt); -NTSTATUS cli_set_user_quota(struct cli_state *cli, int quota_fnum, - SMB_NTQUOTA_STRUCT *pqt); +NTSTATUS cli_set_user_quota(struct cli_state *cli, + int quota_fnum, + SMB_NTQUOTA_LIST *qtl); NTSTATUS cli_list_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_LIST **pqt_list); NTSTATUS cli_get_fs_quota_info(struct cli_state *cli, int quota_fnum, diff --git a/source3/utils/smbcquotas.c b/source3/utils/smbcquotas.c index cda5f922c4f9..c12245735415 100644 --- a/source3/utils/smbcquotas.c +++ b/source3/utils/smbcquotas.c @@ -339,6 +339,7 @@ static int do_quota(struct cli_state *cli, uint32_t fs_attrs = 0; uint16_t quota_fnum = 0; SMB_NTQUOTA_LIST *qtl = NULL; + TALLOC_CTX *qtl_ctx = NULL; SMB_NTQUOTA_STRUCT qt; NTSTATUS status; @@ -386,8 +387,21 @@ static int do_quota(struct cli_state *cli, break; case QUOTA_SETLIM: pqt->sid = qt.sid; + if ((qtl_ctx = talloc_init( + "SMB_USER_QUOTA_SET")) == + NULL) { + return -1; + } + + if (!add_record_to_ntquota_list( + qtl_ctx, pqt, &qtl)) { + TALLOC_FREE(qtl_ctx); + return -1; + } + status = cli_set_user_quota( - cli, quota_fnum, pqt); + cli, quota_fnum, qtl); + free_ntquota_list(&qtl); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_set_user_quota %s\n", nt_errstr(status), -- 2.34.1