s3: smbd: Reformat users of can_write_to_file().
[samba.git] / source3 / smbd / nttrans.c
index 6848d10397f1a18408507e478cb7aed450dc71a6..c44501108abd97742568595be93187476ed66179 100644 (file)
@@ -29,6 +29,9 @@
 #include "auth.h"
 #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;
 
@@ -66,8 +69,8 @@ static void send_nt_replies(connection_struct *conn,
        int params_sent_thistime, data_sent_thistime, total_sent_thistime;
        int alignment_offset = 1;
        int data_alignment_offset = 0;
-       struct smbd_server_connection *sconn = req->sconn;
-       int max_send = sconn->smb1.sessions.max_send;
+       struct smbXsrv_connection *xconn = req->xconn;
+       int max_send = xconn->smb1.sessions.max_send;
 
        /*
         * If there genuinely are no parameters or data to send just send
@@ -82,7 +85,7 @@ static void send_nt_replies(connection_struct *conn,
                                         __LINE__,__FILE__);
                }
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(sconn,
+               if (!srv_send_smb(xconn,
                                (char *)req->outbuf,
                                true, req->seqnum+1,
                                IS_CONN_ENCRYPTED(conn),
@@ -246,7 +249,7 @@ static void send_nt_replies(connection_struct *conn,
 
                /* Send the packet */
                show_msg((char *)req->outbuf);
-               if (!srv_send_smb(sconn,
+               if (!srv_send_smb(xconn,
                                (char *)req->outbuf,
                                true, req->seqnum+1,
                                IS_CONN_ENCRYPTED(conn),
@@ -316,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);
@@ -437,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;
@@ -456,11 +459,11 @@ void reply_ntcreate_and_X(struct smb_request *req)
        struct timespec c_timespec;
        struct timespec a_timespec;
        struct timespec m_timespec;
-       struct timespec write_time_ts;
        NTSTATUS status;
        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,
-                               0,
+                               ucf_flags,
+                               NULL,
                                NULL,
                                &smb_fname);
 
@@ -573,18 +577,26 @@ void reply_ntcreate_and_X(struct smb_request *req)
                create_options,                         /* create_options */
                file_attributes,                        /* file_attributes */
                oplock_request,                         /* oplock_request */
+               NULL,                                   /* lease */
                allocation_size,                        /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               &info);                                 /* pinfo */
+               &info,                                  /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (!NT_STATUS_IS_OK(status)) {
-               if (open_was_deferred(req->sconn, req->mid)) {
+               if (open_was_deferred(req->xconn, req->mid)) {
                        /* We have re-scheduled this call, no error. */
                        goto out;
                }
+               if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+                       bool ok = defer_smb1_sharing_violation(req);
+                       if (ok) {
+                               goto out;
+                       }
+               }
                reply_openerror(req, status);
                goto out;
        }
@@ -655,14 +667,6 @@ void reply_ntcreate_and_X(struct smb_request *req)
                fattr = FILE_ATTRIBUTE_NORMAL;
        }
 
-       /* Deal with other possible opens having a modified
-          write time. JRA. */
-       ZERO_STRUCT(write_time_ts);
-       get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
-       if (!null_timespec(write_time_ts)) {
-               update_stat_ex_mtime(&smb_fname->st, write_time_ts);
-       }
-
        /* Create time. */
        create_timespec = get_create_timespec(conn, fsp, smb_fname);
        a_timespec = smb_fname->st.st_ex_atime;
@@ -676,13 +680,13 @@ void reply_ntcreate_and_X(struct smb_request *req)
                dos_filetime_timespec(&c_timespec);
        }
 
-       put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */
+       put_long_date_full_timespec(conn->ts_res, p, &create_timespec); /* create time. */
        p += 8;
-       put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */
+       put_long_date_full_timespec(conn->ts_res, p, &a_timespec); /* access time */
        p += 8;
-       put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */
+       put_long_date_full_timespec(conn->ts_res, p, &m_timespec); /* write time */
        p += 8;
-       put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */
+       put_long_date_full_timespec(conn->ts_res, p, &c_timespec); /* change time */
        p += 8;
        SIVAL(p,0,fattr); /* File Attributes. */
        p += 4;
@@ -692,17 +696,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) {
@@ -712,14 +719,16 @@ void reply_ntcreate_and_X(struct smb_request *req)
                SSVAL(p,2,file_status);
        }
        p += 4;
-       SCVAL(p,0,fsp->is_directory ? 1 : 0);
+       SCVAL(p,0,fsp->fsp_flags.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 ||
-                   can_write_to_file(conn, smb_fname)) {
+               if (fsp->fsp_flags.is_directory ||
+                   fsp->fsp_flags.can_write ||
+                   can_write_to_file(conn,
+                               smb_fname))
+               {
                        perms = FILE_GENERIC_ALL;
                } else {
                        perms = FILE_GENERIC_READ|FILE_EXECUTE;
@@ -741,9 +750,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;
@@ -751,7 +760,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();
 
        /*
@@ -766,9 +775,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;
@@ -881,6 +906,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;
        }
@@ -890,13 +921,8 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
 
        /* Ensure we have at least one thing set. */
        if ((security_info_sent & (SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL)) == 0) {
-               if (security_info_sent & SECINFO_LABEL) {
-                       /* Only consider SECINFO_LABEL if no other
-                          bits are set. Just like W2K3 we don't
-                          store this. */
-                       return NT_STATUS_OK;
-               }
-               return NT_STATUS_INVALID_PARAMETER;
+               /* Just like W2K3 */
+               return NT_STATUS_OK;
        }
 
        /* Ensure we have the rights to do this. */
@@ -926,6 +952,13 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
                if (!(fsp->access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
                        return NT_STATUS_ACCESS_DENIED;
                }
+               /*
+                * Setting a SACL also requires WRITE_DAC.
+                * See the smbtorture3 SMB2-SACL test.
+                */
+               if (!(fsp->access_mask & SEC_STD_WRITE_DAC)) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
                /* Convert all the generic bits. */
                if (psd->sacl) {
                        security_acl_map_generic(psd->sacl, &file_generic_mapping);
@@ -969,73 +1002,41 @@ NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len,
        return set_sd(fsp, psd, security_info_sent);
 }
 
-/****************************************************************************
- Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
-****************************************************************************/
-
-struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
-{
-       struct ea_list *ea_list_head = NULL;
-       size_t offset = 0;
-
-       if (data_size < 4) {
-               return NULL;
-       }
-
-       while (offset + 4 <= data_size) {
-               size_t next_offset = IVAL(pdata,offset);
-               struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL);
-
-               if (!eal) {
-                       return NULL;
-               }
-
-               DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
-               if (next_offset == 0) {
-                       break;
-               }
-               offset += next_offset;
-       }
-
-       return ea_list_head;
-}
-
 /****************************************************************************
  Reply to a NT_TRANSACT_CREATE call (needs to process SD's).
 ****************************************************************************/
 
 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;
        struct timespec m_timespec;
-       struct timespec write_time_ts;
        struct ea_list *ea_list = NULL;
        NTSTATUS status;
        size_t param_len;
@@ -1043,6 +1044,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"));
@@ -1082,7 +1084,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);
 
        /*
@@ -1091,6 +1093,60 @@ static void call_nt_transact_create(connection_struct *conn,
         */
        create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
 
+       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;
+       }
+
+       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               case_state = set_posix_case_semantics(ctx, conn);
+               if (!case_state) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
+                       goto out;
+               }
+       }
+
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
+       status = filename_convert(ctx,
+                               conn,
+                               fname,
+                               ucf_flags,
+                               NULL,
+                               NULL,
+                               &smb_fname);
+
+       TALLOC_FREE(case_state);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
+                       reply_botherror(req,
+                               NT_STATUS_PATH_NOT_COVERED,
+                               ERRSRV, ERRbadpath);
+                       goto out;
+               }
+               reply_nterror(req, status);
+               goto out;
+       }
+
        /* Ensure the data_len is correct for the sd and ea values given. */
        if ((ea_len + sd_len > data_count)
            || (ea_len > data_count) || (sd_len > data_count)
@@ -1141,43 +1197,27 @@ static void call_nt_transact_create(connection_struct *conn,
                        reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        goto out;
                }
-       }
-
-       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;
-       }
-
-       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
-               case_state = set_posix_case_semantics(ctx, conn);
-               if (!case_state) {
-                       reply_nterror(req, NT_STATUS_NO_MEMORY);
-                       goto out;
-               }
-       }
-
-       status = filename_convert(ctx,
-                               conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
-                               fname,
-                               0,
-                               NULL,
-                               &smb_fname);
 
-       TALLOC_FREE(case_state);
+               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. */
+                               param_len = 101;
+                       } else {
+                               param_len = 69;
+                       }
+                       params = nttrans_realloc(ppparams, param_len);
+                       if(params == NULL) {
+                               reply_nterror(req, NT_STATUS_NO_MEMORY);
+                               goto out;
+                       }
 
-       if (!NT_STATUS_IS_OK(status)) {
-               if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
-                       reply_botherror(req,
-                               NT_STATUS_PATH_NOT_COVERED,
-                               ERRSRV, ERRbadpath);
+                       memset(params, '\0', param_len);
+                       send_nt_replies(conn, req, STATUS_INVALID_EA_NAME,
+                               params, param_len, NULL, 0);
                        goto out;
                }
-               reply_nterror(req, status);
-               goto out;
        }
 
        oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
@@ -1204,18 +1244,26 @@ static void call_nt_transact_create(connection_struct *conn,
                create_options,                         /* create_options */
                file_attributes,                        /* file_attributes */
                oplock_request,                         /* oplock_request */
+               NULL,                                   /* lease */
                allocation_size,                        /* allocation_size */
                0,                                      /* private_flags */
                sd,                                     /* sd */
                ea_list,                                /* ea_list */
                &fsp,                                   /* result */
-               &info);                                 /* pinfo */
+               &info,                                  /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if(!NT_STATUS_IS_OK(status)) {
-               if (open_was_deferred(req->sconn, req->mid)) {
+               if (open_was_deferred(req->xconn, req->mid)) {
                        /* We have re-scheduled this call, no error. */
                        return;
                }
+               if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+                       bool ok = defer_smb1_sharing_violation(req);
+                       if (ok) {
+                               return;
+                       }
+               }
                reply_openerror(req, status);
                goto out;
        }
@@ -1283,14 +1331,6 @@ static void call_nt_transact_create(connection_struct *conn,
                fattr = FILE_ATTRIBUTE_NORMAL;
        }
 
-       /* Deal with other possible opens having a modified
-          write time. JRA. */
-       ZERO_STRUCT(write_time_ts);
-       get_file_infos(fsp->file_id, 0, NULL, &write_time_ts);
-       if (!null_timespec(write_time_ts)) {
-               update_stat_ex_mtime(&smb_fname->st, write_time_ts);
-       }
-
        /* Create time. */
        create_timespec = get_create_timespec(conn, fsp, smb_fname);
        a_timespec = smb_fname->st.st_ex_atime;
@@ -1304,13 +1344,13 @@ static void call_nt_transact_create(connection_struct *conn,
                dos_filetime_timespec(&c_timespec);
        }
 
-       put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */
+       put_long_date_full_timespec(conn->ts_res, p, &create_timespec); /* create time. */
        p += 8;
-       put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */
+       put_long_date_full_timespec(conn->ts_res, p, &a_timespec); /* access time */
        p += 8;
-       put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */
+       put_long_date_full_timespec(conn->ts_res, p, &m_timespec); /* write time */
        p += 8;
-       put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */
+       put_long_date_full_timespec(conn->ts_res, p, &c_timespec); /* change time */
        p += 8;
        SIVAL(p,0,fattr); /* File Attributes. */
        p += 4;
@@ -1320,17 +1360,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) {
@@ -1340,14 +1383,16 @@ static void call_nt_transact_create(connection_struct *conn,
                SSVAL(p,2,file_status);
        }
        p += 4;
-       SCVAL(p,0,fsp->is_directory ? 1 : 0);
+       SCVAL(p,0,fsp->fsp_flags.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 ||
-                   can_write_to_file(conn, smb_fname)) {
+               if (fsp->fsp_flags.is_directory ||
+                   fsp->fsp_flags.can_write ||
+                   can_write_to_file(conn,
+                               smb_fname))
+               {
                        perms = FILE_GENERIC_ALL;
                } else {
                        perms = FILE_GENERIC_READ|FILE_EXECUTE;
@@ -1371,14 +1416,20 @@ static void call_nt_transact_create(connection_struct *conn,
 
 void reply_ntcancel(struct smb_request *req)
 {
+       struct smbXsrv_connection *xconn = req->xconn;
+       struct smbd_server_connection *sconn = req->sconn;
+       bool found;
+
        /*
         * Go through and cancel any pending change notifies.
         */
 
        START_PROFILE(SMBntcancel);
-       srv_cancel_sign_response(req->sconn);
-       remove_pending_change_notify_requests_by_mid(req->sconn, req->mid);
-       remove_pending_lock_requests_by_mid_smb1(req->sconn, req->mid);
+       srv_cancel_sign_response(xconn);
+       found = remove_pending_change_notify_requests_by_mid(sconn, req->mid);
+       if (!found) {
+               smbd_smb1_brl_finish_by_mid(sconn, req->mid);
+       }
 
        DEBUG(3,("reply_ntcancel: cancel called on mid = %llu.\n",
                (unsigned long long)req->mid));
@@ -1396,14 +1447,15 @@ 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;
-       char *parent;
+       struct smb_filename *parent = NULL;
+       bool ok;
 
        if (!CAN_WRITE(conn)) {
                status = NT_STATUS_MEDIA_WRITE_PROTECTED;
@@ -1452,12 +1504,14 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
                NO_OPLOCK,                              /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp1,                                  /* result */
-               &info);                                 /* pinfo */
+               &info,                                  /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (!NT_STATUS_IS_OK(status)) {
                goto out;
@@ -1476,12 +1530,14 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
                0,                                      /* create_options */
                fattr,                                  /* file_attributes */
                NO_OPLOCK,                              /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp2,                                  /* result */
-               &info);                                 /* pinfo */
+               &info,                                  /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (!NT_STATUS_IS_OK(status)) {
                close_file(NULL, fsp1, ERROR_CLOSE);
@@ -1508,8 +1564,12 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
        /* Grrr. We have to do this as open_file_ntcreate adds FILE_ATTRIBUTE_ARCHIVE when it
           creates the file. This isn't the correct thing to do in the copy
           case. JRA */
-       if (!parent_dirname(talloc_tos(), smb_fname_dst->base_name, &parent,
-                           NULL)) {
+
+       ok = parent_smb_fname(talloc_tos(),
+                             smb_fname_dst,
+                             &parent,
+                             NULL);
+       if (!ok) {
                status = NT_STATUS_NO_MEMORY;
                goto out;
        }
@@ -1541,14 +1601,15 @@ void reply_ntrename(struct smb_request *req)
        struct smb_filename *smb_fname_new = NULL;
        char *oldname = NULL;
        char *newname = NULL;
+       const char *dst_original_lcomp = NULL;
        const char *p;
        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;
 
@@ -1570,7 +1631,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;
        }
@@ -1583,7 +1644,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, ':')) {
@@ -1600,16 +1661,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;
        }
 
        /* 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,
@@ -1624,9 +1685,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)) {
@@ -1641,6 +1702,16 @@ void reply_ntrename(struct smb_request *req)
                goto out;
        }
 
+       /* Get the last component of the destination for rename_internals(). */
+       dst_original_lcomp = get_original_lcomp(ctx,
+                                       conn,
+                                       newname,
+                                       ucf_flags_dst);
+       if (dst_original_lcomp == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               goto out;
+       }
+
        if (stream_rename) {
                /* smb_fname_new must be the same as smb_fname_old. */
                TALLOC_FREE(smb_fname_new->base_name);
@@ -1658,11 +1729,17 @@ void reply_ntrename(struct smb_request *req)
 
        switch(rename_type) {
                case RENAME_FLAG_RENAME:
-                       status = rename_internals(ctx, conn, req,
-                                                 smb_fname_old, smb_fname_new,
-                                                 attrs, False, src_has_wcard,
-                                                 dest_has_wcard,
-                                                 DELETE_ACCESS);
+                       status = rename_internals(ctx,
+                                               conn,
+                                               req,
+                                               smb_fname_old,
+                                               smb_fname_new,
+                                               dst_original_lcomp,
+                                               attrs,
+                                               false,
+                                               src_has_wcard,
+                                               dest_has_wcard,
+                                               DELETE_ACCESS);
                        break;
                case RENAME_FLAG_HARD_LINK:
                        if (src_has_wcard || dest_has_wcard) {
@@ -1696,10 +1773,16 @@ void reply_ntrename(struct smb_request *req)
        }
 
        if (!NT_STATUS_IS_OK(status)) {
-               if (open_was_deferred(req->sconn, req->mid)) {
+               if (open_was_deferred(req->xconn, req->mid)) {
                        /* We have re-scheduled this call. */
                        goto out;
                }
+               if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+                       bool ok = defer_smb1_sharing_violation(req);
+                       if (ok) {
+                               goto out;
+                       }
+               }
 
                reply_nterror(req, status);
                goto out;
@@ -1725,17 +1808,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;
 
@@ -1770,15 +1853,17 @@ static void call_nt_transact_notify_change(connection_struct *conn,
                TALLOC_FREE(filter_string);
        }
 
-       if((!fsp->is_directory) || (conn != fsp->conn)) {
+       if((!fsp->fsp_flags.is_directory) || (conn != fsp->conn)) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                return;
        }
 
        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)));
@@ -1832,10 +1917,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;
@@ -1853,9 +1938,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;
@@ -1892,7 +1996,7 @@ static NTSTATUS get_null_nt_acl(TALLOC_CTX *mem_ctx, struct security_descriptor
 
 /****************************************************************************
  Reply to query a security descriptor.
- Callable from SMB2 and SMB2.
+ Callable from SMB1 and SMB2.
  If it returns NT_STATUS_BUFFER_TOO_SMALL, pdata_size is initialized with
  the required size.
 ****************************************************************************/
@@ -1907,6 +2011,8 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
 {
        NTSTATUS status;
        struct security_descriptor *psd = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
+       bool need_to_read_sd = false;
 
        /*
         * Get the permissions to return.
@@ -1915,12 +2021,21 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
        if ((security_info_wanted & SECINFO_SACL) &&
                        !(fsp->access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
                DEBUG(10, ("Access to SACL denied.\n"));
+               TALLOC_FREE(frame);
                return NT_STATUS_ACCESS_DENIED;
        }
 
        if ((security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|SECINFO_GROUP)) &&
                        !(fsp->access_mask & SEC_STD_READ_CONTROL)) {
                DEBUG(10, ("Access to DACL, OWNER, or GROUP denied.\n"));
+               TALLOC_FREE(frame);
+               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;
        }
 
@@ -1929,18 +2044,28 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
                /* Don't return SECINFO_LABEL if anything else was
                   requested. See bug #8458. */
                security_info_wanted &= ~SECINFO_LABEL;
+
+               /*
+                * Only query the file system SD if the caller asks
+                * for any bits. This allows a caller to open without
+                * READ_CONTROL but still issue a query sd. See
+                * smb2.sdread test.
+                */
+               need_to_read_sd = true;
        }
 
-       if (!lp_nt_acl_support(SNUM(conn))) {
-               status = get_null_nt_acl(mem_ctx, &psd);
-       } else if (security_info_wanted & SECINFO_LABEL) {
-               /* Like W2K3 return a null object. */
-               status = get_null_nt_acl(mem_ctx, &psd);
-       } else {
+       if (lp_nt_acl_support(SNUM(conn)) &&
+           ((security_info_wanted & SECINFO_LABEL) == 0) &&
+           need_to_read_sd)
+       {
                status = SMB_VFS_FGET_NT_ACL(
-                       fsp, security_info_wanted, &psd);
+                       fsp, security_info_wanted, frame, &psd);
+       } else {
+               status = get_null_nt_acl(frame, &psd);
        }
+
        if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
                return status;
        }
 
@@ -1989,7 +2114,7 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
        }
 
        if (max_data_count < *psd_size) {
-               TALLOC_FREE(psd);
+               TALLOC_FREE(frame);
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
@@ -1997,11 +2122,11 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn,
                                   ppmarshalled_sd, psd_size);
 
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(psd);
+               TALLOC_FREE(frame);
                return status;
        }
 
-       TALLOC_FREE(psd);
+       TALLOC_FREE(frame);
        return NT_STATUS_OK;
 }
 
@@ -2011,18 +2136,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;
@@ -2057,7 +2182,8 @@ static void call_nt_transact_query_security_desc(connection_struct *conn,
        status = smbd_do_query_security_desc(conn,
                                        talloc_tos(),
                                        fsp,
-                                       security_info_wanted,
+                                       security_info_wanted &
+                                       SMB_SUPPORTED_SECINFO_FLAGS,
                                        max_data_count,
                                        &marshalled_sd,
                                        &sd_size);
@@ -2107,18 +2233,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) {
@@ -2150,8 +2276,8 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
                return;
        }
 
-       status = set_sd_blob(fsp, (uint8 *)data, data_count, security_info_sent);
-
+       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);
                return;
@@ -2168,19 +2294,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();
 
@@ -2239,284 +2365,403 @@ 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);
-
-       /* 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;
-       }
+       uint32_t 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;
+               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 (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;
+               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;
+               }
 
-               case TRANSACT_GET_USER_QUOTA_LIST_START:
+               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;
+               }
 
-                       if (qt_handle->quota_list==NULL &&
-                               qt_handle->tmp_list==NULL) {
-                               start_enum = True;
-                       }
+               *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 (start_enum && vfs_get_user_ntquota_list(fsp,&(qt_handle->quota_list))!=0) {
-                               reply_nterror(req, NT_STATUS_INTERNAL_ERROR);
-                               return;
-                       }
+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;
+       }
 
-                       /* 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;
-                       }
+       *num = 0;
+       *sids = NULL;
 
-                       /* 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(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;
+                       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;
-                       }
-
-                       if (!sid_parse(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 == NULL) {
+                       DBG_ERR("OOM\n");
+                       err = NDR_ERR_ALLOC;
+                       goto done;
+               }
 
-                       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
-                                */
-                       }
+               *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++) {
+                       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)
+{
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
+       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(), lp_sub, 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);
 }
 
 /****************************************************************************
@@ -2525,31 +2770,36 @@ 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)
 {
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        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)),
+                        "[%s]\n", lp_servicename(talloc_tos(), lp_sub, SNUM(conn)),
                         conn->session_info->unix_info->unix_name));
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
-               return;
+               status = NT_STATUS_ACCESS_DENIED;
+               goto error;
        }
 
        /*
@@ -2558,67 +2808,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);
-
-       if (!sid_parse(pdata+40,sid_len,&sid)) {
-               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-               return;
-       }
+       qt.softlim = info.quota_threshold;
 
-       DEBUGADD(8,("SID: %s\n", sid_string_dbg(&sid)));
+       qt.hardlim = info.quota_limit;
 
-       /* 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 */
 
@@ -2764,7 +3005,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;
 
@@ -2913,7 +3154,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);
@@ -2925,7 +3166,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) &&