From b8802e271337e5cec4f13ad4f505ae1905e09ca7 Mon Sep 17 00:00:00 2001 From: Noel Power Date: Fri, 26 May 2017 16:01:53 +0100 Subject: [PATCH] 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 Reviewed-by: Jeremy Allison --- source3/libsmb/cliquota.c | 19 +- source3/smbd/nttrans.c | 670 ++++++++++++++++++++++---------------- source3/smbd/proto.h | 14 + 3 files changed, 407 insertions(+), 296 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,6 +2295,263 @@ 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, + 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; + struct ndr_pull *ndr_pull = NULL; + + 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; + } + 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 == 0 no more sid(s) to read. */ + if (new_offset == 0) { + break; + } + + /* 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; + } + + offset += new_offset; + + /* 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; + } + + *num = i; + + 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; +} + +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; + + qt_handle = + (SMB_NTQUOTA_HANDLE *)fsp->fake_file_handle->private_data; + + 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; + } + + 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)); + } + } + + 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; + } + + *p_data = blob.data; + *p_data_size = blob.length; + return NT_STATUS_OK; +} + /**************************************************************************** Reply to get user quota ****************************************************************************/ @@ -2310,268 +2569,117 @@ 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; + int data_len = 0; + int param_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 = 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; - ZERO_STRUCT(qt); + 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; + 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; } /* maybe we can check the quota_fnum */ - fsp = file_fsp(req, SVAL(params,0)); + 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")); - reply_nterror(req, NT_STATUS_INVALID_HANDLE); - return; + 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; } - /* 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; - - FALL_THROUGH; - 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)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); - } - - 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); - - /* unknown data 8 bytes uint64_t */ - SBIG_UINT(entry,8,(uint64_t)0); /* this is not 0 in windows...-mezte*/ - - /* the used disk space 8 bytes uint64_t */ - SBIG_UINT(entry,16,qt.usedspace); - - /* the soft quotas 8 bytes uint64_t */ - SBIG_UINT(entry,24,qt.softlim); - - /* the hard quotas 8 bytes uint64_t */ - SBIG_UINT(entry,32,qt.hardlim); - - /* and now the SID */ - sid_linearize((uint8_t *)(entry+40), sid_len, &sid); - - break; - - 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... - */ + 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 */ 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);