s3: smbd: Reformat users of can_write_to_file().
[samba.git] / source3 / smbd / nttrans.c
index ddabdda4d6e7b9c54b1d5284cdd5011b7ad3ed22..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),
@@ -142,11 +145,6 @@ static void send_nt_replies(connection_struct *conn,
                             total_sent_thistime + alignment_offset
                             + data_alignment_offset);
 
-               /*
-                * We might have had SMBnttranss in req->inbuf, fix that.
-                */
-               SCVAL(req->outbuf, smb_com, SMBnttrans);
-
                /*
                 * Set total params and data to be sent.
                 */
@@ -251,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),
@@ -284,15 +282,17 @@ static void send_nt_replies(connection_struct *conn,
 ****************************************************************************/
 
 static void nt_open_pipe(char *fname, connection_struct *conn,
-                        struct smb_request *req, int *ppnum)
+                        struct smb_request *req, uint16_t *ppnum)
 {
        files_struct *fsp;
        NTSTATUS status;
 
        DEBUG(4,("nt_open_pipe: Opening pipe %s.\n", fname));
 
-       /* Strip \\ off the name. */
-       fname++;
+       /* Strip \\ off the name if present. */
+       while (fname[0] == '\\') {
+               fname++;
+       }
 
        status = open_np_file(req, fname, &fsp);
        if (!NT_STATUS_IS_OK(status)) {
@@ -317,9 +317,9 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
                                  struct smb_request *req)
 {
        char *fname = NULL;
-       int pnum = -1;
+       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);
@@ -343,7 +343,7 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
                /* This is very strange. We
                 * return 50 words, but only set
-                * the wcnt to 42 ? It's definately
+                * the wcnt to 42 ? It's definitely
                 * what happens on the wire....
                 */
                reply_outbuf(req, 50, 0);
@@ -352,6 +352,9 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
                reply_outbuf(req, 34, 0);
        }
 
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        p = (char *)req->outbuf + smb_vwv2;
        p++;
        SSVAL(p,0,pnum);
@@ -379,8 +382,6 @@ static void do_ntcreate_pipe_open(connection_struct *conn,
        }
 
        DEBUG(5,("do_ntcreate_pipe_open: open pipe = %s\n", fname));
-
-       chain_reply(req);
 }
 
 struct case_semantics_state {
@@ -439,18 +440,18 @@ 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;
-       SMB_OFF_T file_len = 0;
+       uint32_t fattr=0;
+       off_t file_len = 0;
        int info = 0;
        files_struct *fsp = NULL;
        char *p = NULL;
@@ -458,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);
@@ -478,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);
 
@@ -536,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);
 
@@ -575,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;
        }
@@ -625,7 +635,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
                /* This is very strange. We
                 * return 50 words, but only set
-                * the wcnt to 42 ? It's definately
+                * the wcnt to 42 ? It's definitely
                 * what happens on the wire....
                 */
                reply_outbuf(req, 50, 0);
@@ -634,6 +644,9 @@ void reply_ntcreate_and_X(struct smb_request *req)
                reply_outbuf(req, 34, 0);
        }
 
+       SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
+       SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
+
        p = (char *)req->outbuf + smb_vwv2;
 
        SCVAL(p, 0, oplock_granted);
@@ -654,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;
@@ -675,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;
@@ -691,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) {
@@ -711,13 +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 ||
-                   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;
@@ -725,10 +736,9 @@ void reply_ntcreate_and_X(struct smb_request *req)
                SIVAL(p,0,perms);
        }
 
-       DEBUG(5,("reply_ntcreate_and_X: fnum = %d, open name = %s\n",
-               fsp->fnum, smb_fname_str_dbg(smb_fname)));
+       DEBUG(5,("reply_ntcreate_and_X: %s, open name = %s\n",
+               fsp_fnum_dbg(fsp), smb_fname_str_dbg(smb_fname)));
 
-       chain_reply(req);
  out:
        END_PROFILE(SMBntcreateX);
        return;
@@ -740,17 +750,17 @@ 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;
-       int pnum = -1;
+       uint16_t pnum = FNUM_FIELD_INVALID;
        char *p = NULL;
        NTSTATUS status;
        size_t param_len;
-       uint32 flags;
+       uint32_t flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        /*
@@ -765,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;
@@ -830,20 +856,48 @@ static void do_nt_transact_create_pipe(connection_struct *conn,
        return;
 }
 
+/*********************************************************************
+ Windows seems to do canonicalization of inheritance bits. Do the
+ same.
+*********************************************************************/
+
+static void canonicalize_inheritance_bits(struct security_descriptor *psd)
+{
+       bool set_auto_inherited = false;
+
+       /*
+        * We need to filter out the
+        * SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ
+        * bits. If both are set we store SEC_DESC_DACL_AUTO_INHERITED
+        * as this alters whether SEC_ACE_FLAG_INHERITED_ACE is set
+        * when an ACE is inherited. Otherwise we zero these bits out.
+        * See:
+        *
+        * http://social.msdn.microsoft.com/Forums/eu/os_fileservices/thread/11f77b68-731e-407d-b1b3-064750716531
+        *
+        * for details.
+        */
+
+       if ((psd->type & (SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ))
+                       == (SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ)) {
+               set_auto_inherited = true;
+       }
+
+       psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|SEC_DESC_DACL_AUTO_INHERIT_REQ);
+       if (set_auto_inherited) {
+               psd->type |= SEC_DESC_DACL_AUTO_INHERITED;
+       }
+}
+
 /****************************************************************************
  Internal fn to set security descriptors.
 ****************************************************************************/
 
-NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len,
+NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
                       uint32_t security_info_sent)
 {
-       struct security_descriptor *psd = NULL;
        NTSTATUS status;
 
-       if (sd_len == 0) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
        if (!CAN_WRITE(fsp->conn)) {
                return NT_STATUS_ACCESS_DENIED;
        }
@@ -852,10 +906,10 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len,
                return NT_STATUS_OK;
        }
 
-       status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       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) {
@@ -867,13 +921,8 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len,
 
        /* 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. */
@@ -903,12 +952,21 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len,
                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);
                }
        }
 
+       canonicalize_inheritance_bits(psd);
+
        if (DEBUGLEVEL >= 10) {
                DEBUG(10,("set_sd for file %s\n", fsp_str_dbg(fsp)));
                NDR_PRINT_DEBUG(security_descriptor, psd);
@@ -922,34 +980,26 @@ NTSTATUS set_sd(files_struct *fsp, uint8_t *data, uint32_t sd_len,
 }
 
 /****************************************************************************
Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
Internal fn to set security descriptors from a data blob.
 ****************************************************************************/
 
-struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len,
+                      uint32_t security_info_sent)
 {
-       struct ea_list *ea_list_head = NULL;
-       size_t offset = 0;
+       struct security_descriptor *psd = NULL;
+       NTSTATUS status;
 
-       if (data_size < 4) {
-               return NULL;
+       if (sd_len == 0) {
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
-       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;
-               }
+       status = unmarshall_sec_desc(talloc_tos(), data, sd_len, &psd);
 
-               DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
-               if (next_offset == 0) {
-                       break;
-               }
-               offset += next_offset;
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       return ea_list_head;
+       return set_sd(fsp, psd, security_info_sent);
 }
 
 /****************************************************************************
@@ -958,36 +1008,35 @@ struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t
 
 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;
-       SMB_OFF_T file_len = 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;
@@ -995,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"));
@@ -1034,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);
 
        /*
@@ -1043,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)
@@ -1093,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;
@@ -1156,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;
        }
@@ -1235,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;
@@ -1256,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;
@@ -1272,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) {
@@ -1292,13 +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 ||
-                   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;
@@ -1322,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));
@@ -1347,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;
-       SMB_OFF_T ret=-1;
+       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;
@@ -1403,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;
@@ -1427,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);
@@ -1459,15 +1564,19 @@ 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;
        }
        file_set_dosmode(conn, smb_fname_dst, fattr, parent, false);
        TALLOC_FREE(parent);
 
-       if (ret < (SMB_OFF_T)smb_fname_src->st.st_ex_size) {
+       if (ret < (off_t)smb_fname_src->st.st_ex_size) {
                status = NT_STATUS_DISK_FULL;
                goto out;
        }
@@ -1492,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;
 
@@ -1521,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;
        }
@@ -1534,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, ':')) {
@@ -1551,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,
@@ -1575,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)) {
@@ -1592,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);
@@ -1609,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) {
@@ -1647,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;
@@ -1676,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;
 
@@ -1721,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)));
@@ -1738,7 +1872,7 @@ static void call_nt_transact_notify_change(connection_struct *conn,
                }
        }
 
-       if (fsp->notify->num_changes != 0) {
+       if (change_notify_fsp_has_changes(fsp)) {
 
                /*
                 * We've got changes pending, respond immediately
@@ -1783,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;
@@ -1804,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;
@@ -1843,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.
 ****************************************************************************/
@@ -1858,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.
@@ -1865,11 +2020,22 @@ 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;
        }
 
@@ -1878,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;
        }
 
@@ -1938,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;
        }
 
@@ -1946,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;
 }
 
@@ -1960,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;
@@ -2006,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);
@@ -2056,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) {
@@ -2099,8 +2276,8 @@ static void call_nt_transact_set_security_desc(connection_struct *conn,
                return;
        }
 
-       status = set_sd(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;
@@ -2117,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();
 
@@ -2188,282 +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;
+       uint32_t i;
+       TALLOC_CTX *list_ctx = NULL;
 
-       ZERO_STRUCT(qt);
+       list_ctx = talloc_init("quota_sid_list");
 
-       /* access check */
-       if (get_current_uid(conn) != 0) {
-               DEBUG(1,("get_user_quota: access_denied service [%s] user "
-                        "[%s]\n", lp_servicename(SNUM(conn)),
-                        conn->session_info->unix_info->unix_name));
-               reply_nterror(req, NT_STATUS_ACCESS_DENIED);
-               return;
+       if (list_ctx == NULL) {
+               DBG_ERR("failed to allocate\n");
+               return NDR_ERR_ALLOC;
        }
 
-       /*
-        * Ensure minimum number of parameters sent.
-        */
-
-       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;
-       }
-
-       /* 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: fnum %d unknown level 0x%04hX\n",fsp->fnum,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);
 }
 
 /****************************************************************************
@@ -2472,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(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;
        }
 
        /*
@@ -2505,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);
+       qt.softlim = info.quota_threshold;
 
-       /* the hard quotas 8 bytes (uint64_t)*/
-       qt.hardlim = BVAL(pdata,32);
+       qt.hardlim = info.quota_limit;
 
-       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 */
 
@@ -2711,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;
 
@@ -2860,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);
@@ -2872,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) &&
@@ -2919,6 +3213,12 @@ void reply_nttranss(struct smb_request *req)
 
        show_msg((const char *)req->inbuf);
 
+       /* Windows clients expect all replies to
+          an NT transact secondary (SMBnttranss 0xA1)
+          to have a command code of NT transact
+          (SMBnttrans 0xA0). See bug #8989 for details. */
+       req->cmd = SMBnttrans;
+
        if (req->wct < 18) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                END_PROFILE(SMBnttranss);