s3:smbd: fix max_buffer handling of initial notify requests
[samba.git] / source3 / smbd / nttrans.c
index 4423a44cbeabb183d8a5964747f856a6cf7360dd..8bb121a13515fe6c43a36cf9550485d642200e94 100644 (file)
@@ -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;
 
@@ -317,7 +319,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
        char *fname = NULL;
        uint16_t pnum = FNUM_FIELD_INVALID;
        char *p = NULL;
-       uint32 flags = IVAL(req->vwv+3, 1);
+       uint32_t flags = IVAL(req->vwv+3, 1);
        TALLOC_CTX *ctx = talloc_tos();
 
        srvstr_pull_req_talloc(ctx, req, &fname, req->buf, STR_TERMINATE);
@@ -438,17 +440,17 @@ void reply_ntcreate_and_X(struct smb_request *req)
        connection_struct *conn = req->conn;
        struct smb_filename *smb_fname = NULL;
        char *fname = NULL;
-       uint32 flags;
-       uint32 access_mask;
-       uint32 file_attributes;
-       uint32 share_access;
-       uint32 create_disposition;
-       uint32 create_options;
-       uint16 root_dir_fid;
+       uint32_t flags;
+       uint32_t access_mask;
+       uint32_t file_attributes;
+       uint32_t share_access;
+       uint32_t create_disposition;
+       uint32_t create_options;
+       uint16_t root_dir_fid;
        uint64_t allocation_size;
        /* Breakout the oplock request bits so we can set the
           reply bits separately. */
-       uint32 fattr=0;
+       uint32_t fattr=0;
        off_t file_len = 0;
        int info = 0;
        files_struct *fsp = NULL;
@@ -461,6 +463,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
        int oplock_request;
        uint8_t oplock_granted = NO_OPLOCK_RETURN;
        struct case_semantics_state *case_state = NULL;
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBntcreateX);
@@ -476,7 +479,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
        share_access = IVAL(req->vwv+15, 1);
        create_disposition = IVAL(req->vwv+17, 1);
        create_options = IVAL(req->vwv+19, 1);
-       root_dir_fid = (uint16)IVAL(req->vwv+5, 1);
+       root_dir_fid = (uint16_t)IVAL(req->vwv+5, 1);
 
        allocation_size = BVAL(req->vwv+9, 1);
 
@@ -534,11 +537,12 @@ void reply_ntcreate_and_X(struct smb_request *req)
                }
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
        status = filename_convert(ctx,
                                conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
-                               UCF_PREP_CREATEFILE,
+                               ucf_flags,
+                               NULL,
                                NULL,
                                &smb_fname);
 
@@ -686,17 +690,20 @@ void reply_ntcreate_and_X(struct smb_request *req)
        p += 8;
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
                uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG);
-               size_t num_names = 0;
                unsigned int num_streams = 0;
                struct stream_struct *streams = NULL;
 
-               /* Do we have any EA's ? */
-               status = get_ea_names_from_file(ctx, conn, fsp,
-                               smb_fname->base_name, NULL, &num_names);
-               if (NT_STATUS_IS_OK(status) && num_names) {
-                       file_status &= ~NO_EAS;
+               if (lp_ea_support(SNUM(conn))) {
+                       size_t num_names = 0;
+                       /* Do we have any EA's ? */
+                       status = get_ea_names_from_file(
+                           ctx, conn, fsp, smb_fname, NULL, &num_names);
+                       if (NT_STATUS_IS_OK(status) && num_names) {
+                               file_status &= ~NO_EAS;
+                       }
                }
-               status = vfs_streaminfo(conn, NULL, smb_fname->base_name, ctx,
+
+               status = vfs_streaminfo(conn, NULL, smb_fname, ctx,
                        &num_streams, &streams);
                /* There is always one stream, ::$DATA. */
                if (NT_STATUS_IS_OK(status) && num_streams > 1) {
@@ -709,7 +716,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
        SCVAL(p,0,fsp->is_directory ? 1 : 0);
 
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
-               uint32 perms = 0;
+               uint32_t perms = 0;
                p += 25;
                if (fsp->is_directory ||
                    fsp->can_write ||
@@ -735,9 +742,9 @@ void reply_ntcreate_and_X(struct smb_request *req)
 
 static void do_nt_transact_create_pipe(connection_struct *conn,
                                       struct smb_request *req,
-                                      uint16 **ppsetup, uint32 setup_count,
-                                      char **ppparams, uint32 parameter_count,
-                                      char **ppdata, uint32 data_count)
+                                      uint16_t **ppsetup, uint32_t setup_count,
+                                      char **ppparams, uint32_t parameter_count,
+                                      char **ppdata, uint32_t data_count)
 {
        char *fname = NULL;
        char *params = *ppparams;
@@ -745,7 +752,7 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
        char *p = NULL;
        NTSTATUS status;
        size_t param_len;
-       uint32 flags;
+       uint32_t flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        /*
@@ -760,9 +767,25 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
 
        flags = IVAL(params,0);
 
-       srvstr_get_path(ctx, params, req->flags2, &fname, params+53,
-                       parameter_count-53, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       params+53,
+                       parameter_count-53,
+                       STR_TERMINATE,
                        &status);
+       } else {
+               srvstr_get_path(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       params+53,
+                       parameter_count-53,
+                       STR_TERMINATE,
+                       &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
@@ -875,6 +898,12 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
                return NT_STATUS_OK;
        }
 
+       if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
+               DEBUG(10, ("ACL set on symlink %s denied.\n",
+                       fsp_str_dbg(fsp)));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (psd->owner_sid == NULL) {
                security_info_sent &= ~SECINFO_OWNER;
        }
@@ -964,31 +993,31 @@ NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len,
 
 static void call_nt_transact_create(connection_struct *conn,
                                    struct smb_request *req,
-                                   uint16 **ppsetup, uint32 setup_count,
-                                   char **ppparams, uint32 parameter_count,
-                                   char **ppdata, uint32 data_count,
-                                   uint32 max_data_count)
+                                   uint16_t **ppsetup, uint32_t setup_count,
+                                   char **ppparams, uint32_t parameter_count,
+                                   char **ppdata, uint32_t data_count,
+                                   uint32_t max_data_count)
 {
        struct smb_filename *smb_fname = NULL;
        char *fname = NULL;
        char *params = *ppparams;
        char *data = *ppdata;
        /* Breakout the oplock request bits so we can set the reply bits separately. */
-       uint32 fattr=0;
+       uint32_t fattr=0;
        off_t file_len = 0;
        int info = 0;
        files_struct *fsp = NULL;
        char *p = NULL;
-       uint32 flags;
-       uint32 access_mask;
-       uint32 file_attributes;
-       uint32 share_access;
-       uint32 create_disposition;
-       uint32 create_options;
-       uint32 sd_len;
+       uint32_t flags;
+       uint32_t access_mask;
+       uint32_t file_attributes;
+       uint32_t share_access;
+       uint32_t create_disposition;
+       uint32_t create_options;
+       uint32_t sd_len;
        struct security_descriptor *sd = NULL;
-       uint32 ea_len;
-       uint16 root_dir_fid;
+       uint32_t ea_len;
+       uint16_t root_dir_fid;
        struct timespec create_timespec;
        struct timespec c_timespec;
        struct timespec a_timespec;
@@ -1000,6 +1029,7 @@ static void call_nt_transact_create(connection_struct *conn,
        int oplock_request;
        uint8_t oplock_granted;
        struct case_semantics_state *case_state = NULL;
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        DEBUG(5,("call_nt_transact_create\n"));
@@ -1039,7 +1069,7 @@ static void call_nt_transact_create(connection_struct *conn,
        create_options = IVAL(params,32);
        sd_len = IVAL(params,36);
        ea_len = IVAL(params,40);
-       root_dir_fid = (uint16)IVAL(params,4);
+       root_dir_fid = (uint16_t)IVAL(params,4);
        allocation_size = BVAL(params,12);
 
        /*
@@ -1048,9 +1078,25 @@ static void call_nt_transact_create(connection_struct *conn,
         */
        create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
 
-       srvstr_get_path(ctx, params, req->flags2, &fname,
-                       params+53, parameter_count-53,
-                       STR_TERMINATE, &status);
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       params+53,
+                       parameter_count-53,
+                       STR_TERMINATE,
+                       &status);
+       } else {
+               srvstr_get_path(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       params+53,
+                       parameter_count-53,
+                       STR_TERMINATE,
+                       &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                goto out;
@@ -1064,11 +1110,12 @@ static void call_nt_transact_create(connection_struct *conn,
                }
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
        status = filename_convert(ctx,
                                conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
-                               UCF_PREP_CREATEFILE,
+                               ucf_flags,
+                               NULL,
                                NULL,
                                &smb_fname);
 
@@ -1136,7 +1183,8 @@ static void call_nt_transact_create(connection_struct *conn,
                        goto out;
                }
 
-               if (ea_list_has_invalid_name(ea_list)) {
+               if (!req->posix_pathnames &&
+                               ea_list_has_invalid_name(ea_list)) {
                        /* Realloc the size of parameters and data we will return */
                        if (flags & EXTENDED_RESPONSE_REQUIRED) {
                                /* Extended response is 32 more byyes. */
@@ -1291,17 +1339,20 @@ static void call_nt_transact_create(connection_struct *conn,
        p += 8;
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
                uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG);
-               size_t num_names = 0;
                unsigned int num_streams = 0;
                struct stream_struct *streams = NULL;
 
-               /* Do we have any EA's ? */
-               status = get_ea_names_from_file(ctx, conn, fsp,
-                               smb_fname->base_name, NULL, &num_names);
-               if (NT_STATUS_IS_OK(status) && num_names) {
-                       file_status &= ~NO_EAS;
+               if (lp_ea_support(SNUM(conn))) {
+                       size_t num_names = 0;
+                       /* Do we have any EA's ? */
+                       status = get_ea_names_from_file(
+                           ctx, conn, fsp, smb_fname, NULL, &num_names);
+                       if (NT_STATUS_IS_OK(status) && num_names) {
+                               file_status &= ~NO_EAS;
+                       }
                }
-               status = vfs_streaminfo(conn, NULL, smb_fname->base_name, ctx,
+
+               status = vfs_streaminfo(conn, NULL, smb_fname, ctx,
                        &num_streams, &streams);
                /* There is always one stream, ::$DATA. */
                if (NT_STATUS_IS_OK(status) && num_streams > 1) {
@@ -1314,7 +1365,7 @@ static void call_nt_transact_create(connection_struct *conn,
        SCVAL(p,0,fsp->is_directory ? 1 : 0);
 
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
-               uint32 perms = 0;
+               uint32_t perms = 0;
                p += 25;
                if (fsp->is_directory ||
                    fsp->can_write ||
@@ -1370,10 +1421,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
                                struct smb_request *req,
                                struct smb_filename *smb_fname_src,
                                struct smb_filename *smb_fname_dst,
-                               uint32 attrs)
+                               uint32_t attrs)
 {
        files_struct *fsp1,*fsp2;
-       uint32 fattr;
+       uint32_t fattr;
        int info;
        off_t ret=-1;
        NTSTATUS status = NT_STATUS_OK;
@@ -1523,10 +1574,10 @@ void reply_ntrename(struct smb_request *req)
        NTSTATUS status;
        bool src_has_wcard = False;
        bool dest_has_wcard = False;
-       uint32 attrs;
-       uint32_t ucf_flags_src = 0;
-       uint32_t ucf_flags_dst = 0;
-       uint16 rename_type;
+       uint32_t attrs;
+       uint32_t ucf_flags_src = ucf_flags_from_smb_request(req);
+       uint32_t ucf_flags_dst = ucf_flags_from_smb_request(req);
+       uint16_t rename_type;
        TALLOC_CTX *ctx = talloc_tos();
        bool stream_rename = false;
 
@@ -1548,7 +1599,7 @@ void reply_ntrename(struct smb_request *req)
                goto out;
        }
 
-       if (ms_has_wild(oldname)) {
+       if (!req->posix_pathnames && ms_has_wild(oldname)) {
                reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
                goto out;
        }
@@ -1561,7 +1612,7 @@ void reply_ntrename(struct smb_request *req)
                goto out;
        }
 
-       if (!lp_posix_pathnames()) {
+       if (!req->posix_pathnames) {
                /* The newname must begin with a ':' if the
                   oldname contains a ':'. */
                if (strchr_m(oldname, ':')) {
@@ -1578,16 +1629,16 @@ void reply_ntrename(struct smb_request *req)
         * destination's last component.
         */
        if (rename_type == RENAME_FLAG_RENAME) {
-               ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP;
-               ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP;
+               ucf_flags_src |= UCF_COND_ALLOW_WCARD_LCOMP;
+               ucf_flags_dst |= UCF_COND_ALLOW_WCARD_LCOMP | UCF_SAVE_LCOMP;
        }
 
        /* rename_internals() calls unix_convert(), so don't call it here. */
        status = filename_convert(ctx, conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  oldname,
                                  ucf_flags_src,
                                  NULL,
+                                 NULL,
                                  &smb_fname_old);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,
@@ -1602,9 +1653,9 @@ void reply_ntrename(struct smb_request *req)
        }
 
        status = filename_convert(ctx, conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  newname,
                                  ucf_flags_dst,
+                                 NULL,
                                  &dest_has_wcard,
                                  &smb_fname_new);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1703,17 +1754,17 @@ static void smbd_smb1_notify_reply(struct smb_request *req,
 
 static void call_nt_transact_notify_change(connection_struct *conn,
                                           struct smb_request *req,
-                                          uint16 **ppsetup,
-                                          uint32 setup_count,
+                                          uint16_t **ppsetup,
+                                          uint32_t setup_count,
                                           char **ppparams,
-                                          uint32 parameter_count,
-                                          char **ppdata, uint32 data_count,
-                                          uint32 max_data_count,
-                                          uint32 max_param_count)
+                                          uint32_t parameter_count,
+                                          char **ppdata, uint32_t data_count,
+                                          uint32_t max_data_count,
+                                          uint32_t max_param_count)
 {
-       uint16 *setup = *ppsetup;
+       uint16_t *setup = *ppsetup;
        files_struct *fsp;
-       uint32 filter;
+       uint32_t filter;
        NTSTATUS status;
        bool recursive;
 
@@ -1755,8 +1806,10 @@ static void call_nt_transact_notify_change(connection_struct *conn,
 
        if (fsp->notify == NULL) {
 
-               status = change_notify_create(fsp, filter, recursive);
-
+               status = change_notify_create(fsp,
+                                             max_param_count,
+                                             filter,
+                                             recursive);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(10, ("change_notify_create returned %s\n",
                                   nt_errstr(status)));
@@ -1810,10 +1863,10 @@ static void call_nt_transact_notify_change(connection_struct *conn,
 
 static void call_nt_transact_rename(connection_struct *conn,
                                    struct smb_request *req,
-                                   uint16 **ppsetup, uint32 setup_count,
-                                   char **ppparams, uint32 parameter_count,
-                                   char **ppdata, uint32 data_count,
-                                   uint32 max_data_count)
+                                   uint16_t **ppsetup, uint32_t setup_count,
+                                   char **ppparams, uint32_t parameter_count,
+                                   char **ppdata, uint32_t data_count,
+                                   uint32_t max_data_count)
 {
        char *params = *ppparams;
        char *new_name = NULL;
@@ -1831,9 +1884,28 @@ static void call_nt_transact_rename(connection_struct *conn,
        if (!check_fsp(conn, req, fsp)) {
                return;
        }
-       srvstr_get_path_wcard(ctx, params, req->flags2, &new_name, params+4,
-                             parameter_count - 4,
-                             STR_TERMINATE, &status, &dest_has_wcard);
+       if (req->posix_pathnames) {
+               srvstr_get_path_wcard_posix(ctx,
+                               params,
+                               req->flags2,
+                               &new_name,
+                               params+4,
+                               parameter_count - 4,
+                               STR_TERMINATE,
+                               &status,
+                               &dest_has_wcard);
+       } else {
+               srvstr_get_path_wcard(ctx,
+                               params,
+                               req->flags2,
+                               &new_name,
+                               params+4,
+                               parameter_count - 4,
+                               STR_TERMINATE,
+                               &status,
+                               &dest_has_wcard);
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
@@ -1905,6 +1977,13 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
+               DEBUG(10, ("ACL get on symlink %s denied.\n",
+                       fsp_str_dbg(fsp)));
+               TALLOC_FREE(frame);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
                        SECINFO_GROUP|SECINFO_SACL)) {
                /* Don't return SECINFO_LABEL if anything else was
@@ -1993,18 +2072,18 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
 
 static void call_nt_transact_query_security_desc(connection_struct *conn,
                                                 struct smb_request *req,
-                                                uint16 **ppsetup,
-                                                uint32 setup_count,
+                                                uint16_t **ppsetup,
+                                                uint32_t setup_count,
                                                 char **ppparams,
-                                                uint32 parameter_count,
+                                                uint32_t parameter_count,
                                                 char **ppdata,
-                                                uint32 data_count,
-                                                uint32 max_data_count)
+                                                uint32_t data_count,
+                                                uint32_t max_data_count)
 {
        char *params = *ppparams;
        char *data = *ppdata;
        size_t sd_size = 0;
-       uint32 security_info_wanted;
+       uint32_t security_info_wanted;
        files_struct *fsp = NULL;
        NTSTATUS status;
        uint8_t *marshalled_sd = NULL;
@@ -2090,18 +2169,18 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
 
 static void call_nt_transact_set_security_desc(connection_struct *conn,
                                               struct smb_request *req,
-                                              uint16 **ppsetup,
-                                              uint32 setup_count,
+                                              uint16_t **ppsetup,
+                                              uint32_t setup_count,
                                               char **ppparams,
-                                              uint32 parameter_count,
+                                              uint32_t parameter_count,
                                               char **ppdata,
-                                              uint32 data_count,
-                                              uint32 max_data_count)
+                                              uint32_t data_count,
+                                              uint32_t max_data_count)
 {
        char *params= *ppparams;
        char *data = *ppdata;
        files_struct *fsp = NULL;
-       uint32 security_info_sent = 0;
+       uint32_t security_info_sent = 0;
        NTSTATUS status;
 
        if(parameter_count < 8) {
@@ -2133,7 +2212,7 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
                return;
        }
 
-       status = set_sd_blob(fsp, (uint8 *)data, data_count,
+       status = set_sd_blob(fsp, (uint8_t *)data, data_count,
                             security_info_sent & SMB_SUPPORTED_SECINFO_FLAGS);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
@@ -2151,19 +2230,19 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
 
 static void call_nt_transact_ioctl(connection_struct *conn,
                                   struct smb_request *req,
-                                  uint16 **ppsetup, uint32 setup_count,
-                                  char **ppparams, uint32 parameter_count,
-                                  char **ppdata, uint32 data_count,
-                                  uint32 max_data_count)
+                                  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 status;
-       uint32 function;
-       uint16 fidnum;
+       uint32_t function;
+       uint16_t fidnum;
        files_struct *fsp;
-       uint8 isFSctl;
-       uint8 compfilter;
+       uint8_t isFSctl;
+       uint8_t compfilter;
        char *out_data = NULL;
-       uint32 out_data_len = 0;
+       uint32_t out_data_len = 0;
        char *pdata = *ppdata;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -2222,284 +2301,401 @@ 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 **ppsetup,
-                                           uint32 setup_count,
-                                           char **ppparams,
-                                           uint32 parameter_count,
-                                           char **ppdata,
-                                           uint32 data_count,
-                                           uint32 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 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);
+       uint32_t i;
+       TALLOC_CTX *list_ctx = NULL;
 
-       /* access check */
-       if (get_current_uid(conn) != 0) {
-               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;
-       }
-
-       /*
-        * 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;
+               bool 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 (!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;
+               }
 
-                       if (qt_handle->quota_list!=NULL &&
-                           qt_handle->tmp_list==NULL) {
 
-                               /* free the list */
-                               free_ntquota_list(&(qt_handle->quota_list));
+               list_item = talloc_zero(list_ctx, SMB_NTQUOTA_LIST);
+               if (list_item == NULL) {
+                       DBG_ERR("failed to allocate\n");
+                       return NDR_ERR_ALLOC;
+               }
 
-                               /* 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;
-                               }
+               ok = sid_to_uid(&sids[i], &list_item->uid);
+               if (!ok) {
+                       struct dom_sid_buf buf;
+                       DBG_WARNING("Could not convert SID %s to uid\n",
+                                   dom_sid_str_buf(&sids[i], &buf));
+                       /* No idea what to return here... */
+                       return NDR_ERR_INVALID_POINTER;
+               }
 
-                               data_len = 0;
-                               SIVAL(params,0,data_len);
+               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;
+               }
 
-                               break;
-                       }
+               *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;
+}
 
-                       start_enum = False;
+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;
+       }
 
-               case TRANSACT_GET_USER_QUOTA_LIST_START:
+       *num = 0;
+       *sids = NULL;
 
-                       if (qt_handle->quota_list==NULL &&
-                               qt_handle->tmp_list==NULL) {
-                               start_enum = True;
-                       }
+       if (sidlistlength) {
+               uint32_t offset = 0;
+               struct ndr_pull *ndr_pull = NULL;
 
-                       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;
+               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;
                        }
-
-                       /* 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;
+                       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;
                        }
-
-                       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;
+                       item = talloc_zero(list_ctx, struct sid_list_elem);
+                       if (!item) {
+                               DBG_ERR("OOM\n");
+                               err = NDR_ERR_ALLOC;
+                               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(entry+40, sid_len, &tmp_list->quotas->sid);
+                       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;
 
-                       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 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;
+                       offset += new_offset;
 
-                       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;
+                       /* 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 == NULL) {
+                       DBG_ERR("OOM\n");
+                       err = NDR_ERR_ALLOC;
+                       goto done;
+               }
 
-                       if (!sid_parse(pdata+8,sid_len,&sid)) {
-                               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-                               return;
-                       }
+               *num = i;
 
-                       if (vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &qt)!=0) {
-                               ZERO_STRUCT(qt);
-                               /*
-                                * we have to return zero's in all fields
-                                * instead of returning an error here
-                                * --metze
-                                */
-                       }
-
-                       /* 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++) {
+                       struct dom_sid_buf buf;
+                       (*sids)[i] = iter->sid;
+                       DBG_DEBUG("quota SID[%u] %s\n",
+                               (unsigned int)i,
+                               dom_sid_str_buf(&iter->sid, &buf));
+               }
+       }
+       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(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);
 }
 
 /****************************************************************************
@@ -2508,31 +2704,34 @@ static void call_nt_transact_get_user_quota(connection_struct *conn,
 
 static void call_nt_transact_set_user_quota(connection_struct *conn,
                                            struct smb_request *req,
-                                           uint16 **ppsetup,
-                                           uint32 setup_count,
+                                           uint16_t **ppsetup,
+                                           uint32_t setup_count,
                                            char **ppparams,
-                                           uint32 parameter_count,
+                                           uint32_t parameter_count,
                                            char **ppdata,
-                                           uint32 data_count,
-                                           uint32 max_data_count)
+                                           uint32_t data_count,
+                                           uint32_t max_data_count)
 {
        char *params = *ppparams;
        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 */
-       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));
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
-               return;
+               status = NT_STATUS_ACCESS_DENIED;
+               goto error;
        }
 
        /*
@@ -2541,67 +2740,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
-        */
+       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(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 */
 
@@ -2747,7 +2937,7 @@ void reply_nttrans(struct smb_request *req)
        uint32_t psoff;
        uint32_t dscnt;
        uint32_t dsoff;
-       uint16 function_code;
+       uint16_t function_code;
        NTSTATUS result;
        struct trans_state *state;
 
@@ -2896,7 +3086,7 @@ void reply_nttrans(struct smb_request *req)
                        goto bad_param;
                }
 
-               state->setup = (uint16 *)TALLOC(state, state->setup_count);
+               state->setup = (uint16_t *)TALLOC(state, state->setup_count);
                if (state->setup == NULL) {
                        DEBUG(0,("reply_nttrans : Out of memory\n"));
                        SAFE_FREE(state->data);
@@ -2908,7 +3098,7 @@ void reply_nttrans(struct smb_request *req)
                }
 
                memcpy(state->setup, req->vwv+19, state->setup_count);
-               dump_data(10, (uint8 *)state->setup, state->setup_count);
+               dump_data(10, (uint8_t *)state->setup, state->setup_count);
        }
 
        if ((state->received_data == state->total_data) &&