s3:smbd: Change get_ea_names_from_file() to take a const smb_filename * parameter...
[kai/samba-autobuild/.git] / source3 / smbd / trans2.c
index a216f15cd3833cc60c9c35506b8cf8afc16b627e..b03094d19a069f79112750d362bb59ccf09bc7b1 100644 (file)
@@ -24,6 +24,7 @@
 */
 
 #include "includes.h"
+#include "ntioctl.h"
 #include "system/filesys.h"
 #include "version.h"
 #include "smbd/smbd.h"
@@ -38,6 +39,8 @@
 #include "smbprofile.h"
 #include "rpc_server/srv_pipe_hnd.h"
 #include "printing.h"
+#include "lib/util_ea.h"
+#include "lib/readdir_attr.h"
 
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
@@ -51,6 +54,43 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
                                files_struct *fsp,
                                const SMB_STRUCT_STAT *psbuf);
 
+/****************************************************************************
+ Check if an open file handle or pathname is a symlink.
+****************************************************************************/
+
+static NTSTATUS refuse_symlink(connection_struct *conn,
+                       const files_struct *fsp,
+                       const char *name)
+{
+       SMB_STRUCT_STAT sbuf;
+       const SMB_STRUCT_STAT *pst = NULL;
+
+       if (fsp) {
+               pst = &fsp->fsp_name->st;
+       } else {
+               int ret = vfs_stat_smb_basename(conn,
+                               name,
+                               &sbuf);
+               if (ret == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+               pst = &sbuf;
+       }
+       if (S_ISLNK(pst->st_ex_mode)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_OK;
+}
+
+NTSTATUS check_access_fsp(const struct files_struct *fsp,
+                         uint32_t access_mask)
+{
+       if (!(fsp->access_mask & access_mask)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_OK;
+}
+
 /********************************************************************
  The canonical "check access" based on object handle or path function.
 ********************************************************************/
@@ -60,20 +100,16 @@ NTSTATUS check_access(connection_struct *conn,
                                const struct smb_filename *smb_fname,
                                uint32_t access_mask)
 {
+       NTSTATUS status;
+
        if (fsp) {
-               if (!(fsp->access_mask & access_mask)) {
-                       return NT_STATUS_ACCESS_DENIED;
-               }
+               status = check_access_fsp(fsp, access_mask);
        } else {
-               NTSTATUS status = smbd_check_access_rights(conn,
-                                       smb_fname,
-                                       false,
-                                       access_mask);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+               status = smbd_check_access_rights(conn, smb_fname,
+                                                 false, access_mask);
        }
-       return NT_STATUS_OK;
+
+       return status;
 }
 
 /********************************************************************
@@ -118,7 +154,7 @@ uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf)
  Refuse to allow clients to overwrite our private xattrs.
 ****************************************************************************/
 
-static bool samba_private_attr_name(const char *unix_ea_name)
+bool samba_private_attr_name(const char *unix_ea_name)
 {
        static const char * const prohibited_ea_names[] = {
                SAMBA_POSIX_INHERITANCE_EA_NAME,
@@ -177,7 +213,7 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
        }
 
        DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
-       dump_data(10, (uint8 *)val, sizeret);
+       dump_data(10, (uint8_t *)val, sizeret);
 
        pea->flags = 0;
        if (strnequal(ea_name, "user.", 5)) {
@@ -194,9 +230,12 @@ NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
-                               files_struct *fsp, const char *fname,
-                               char ***pnames, size_t *pnum_names)
+NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx,
+                               connection_struct *conn,
+                               files_struct *fsp,
+                               const struct smb_filename *smb_fname,
+                               char ***pnames,
+                               size_t *pnum_names)
 {
        /* Get a list of all xattrs. Max namesize is 64k. */
        size_t ea_namelist_size = 1024;
@@ -206,12 +245,22 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
        char **names, **tmp;
        size_t num_names;
        ssize_t sizeret = -1;
+       NTSTATUS status;
+
+       if (pnames) {
+               *pnames = NULL;
+       }
+       *pnum_names = 0;
 
        if (!lp_ea_support(SNUM(conn))) {
-               if (pnames) {
-                       *pnames = NULL;
-               }
-               *pnum_names = 0;
+               return NT_STATUS_OK;
+       }
+
+       status = refuse_symlink(conn, fsp, smb_fname->base_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               /*
+                * Just return no EA's on a symlink.
+                */
                return NT_STATUS_OK;
        }
 
@@ -239,8 +288,10 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
                        sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
                                                     ea_namelist_size);
                } else {
-                       sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
-                                                   ea_namelist_size);
+                       sizeret = SMB_VFS_LISTXATTR(conn,
+                                       smb_fname->base_name,
+                                       ea_namelist,
+                                       ea_namelist_size);
                }
 
                if ((sizeret == -1) && (errno == ERANGE)) {
@@ -256,15 +307,11 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
                return map_nt_error_from_unix(errno);
        }
 
-       DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
-                  (unsigned int)sizeret));
+       DEBUG(10, ("%s: ea_namelist size = %u\n",
+                  __func__, (unsigned int)sizeret));
 
        if (sizeret == 0) {
                TALLOC_FREE(names);
-               if (pnames) {
-                       *pnames = NULL;
-               }
-               *pnum_names = 0;
                return NT_STATUS_OK;
        }
 
@@ -313,8 +360,12 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
  Return a linked list of the total EA's. Plus the total size
 ****************************************************************************/
 
-static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
-                                     const char *fname, size_t *pea_total_len, struct ea_list **ea_list)
+static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx,
+                               connection_struct *conn,
+                               files_struct *fsp,
+                               const struct smb_filename *smb_fname,
+                               size_t *pea_total_len,
+                               struct ea_list **ea_list)
 {
        /* Get a list of all xattrs. Max namesize is 64k. */
        size_t i, num_names;
@@ -325,8 +376,12 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc
        *pea_total_len = 0;
        *ea_list = NULL;
 
-       status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
-                                       &names, &num_names);
+       status = get_ea_names_from_file(talloc_tos(),
+                               conn,
+                               fsp,
+                               smb_fname,
+                               &names,
+                               &num_names);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -359,9 +414,12 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc
                        return NT_STATUS_NO_MEMORY;
                }
 
-               status = get_ea_value(listp, conn, fsp,
-                                     fname, names[i],
-                                     &listp->ea);
+               status = get_ea_value(listp,
+                                       conn,
+                                       fsp,
+                                       smb_fname->base_name,
+                                       names[i],
+                                       &listp->ea);
 
                if (!NT_STATUS_IS_OK(status)) {
                        TALLOC_FREE(listp);
@@ -386,7 +444,7 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc
                          "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
                          (unsigned int)listp->ea.value.length));
 
-               DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
+               DLIST_ADD_END(ea_list_head, listp);
 
        }
 
@@ -416,7 +474,12 @@ static NTSTATUS get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *co
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       return get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, pea_total_len, ea_list);
+       return get_ea_list_from_file_path(mem_ctx,
+                               conn,
+                               fsp,
+                               smb_fname,
+                               pea_total_len,
+                               ea_list);
 }
 
 /****************************************************************************
@@ -559,7 +622,12 @@ static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp,
        if (is_ntfs_stream_smb_fname(smb_fname)) {
                fsp = NULL;
        }
-       (void)get_ea_list_from_file_path(mem_ctx, conn, fsp, smb_fname->base_name, &total_ea_len, &ea_list);
+       (void)get_ea_list_from_file_path(mem_ctx,
+                               conn,
+                               fsp,
+                               smb_fname,
+                               &total_ea_len,
+                               &ea_list);
        if(conn->sconn->using_smb2) {
                NTSTATUS status;
                unsigned int ret_data_size;
@@ -588,12 +656,20 @@ static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp,
  Ensure the EA name is case insensitive by matching any existing EA name.
 ****************************************************************************/
 
-static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
+static void canonicalize_ea_name(connection_struct *conn,
+                       files_struct *fsp,
+                       const struct smb_filename *smb_fname,
+                       fstring unix_ea_name)
 {
        size_t total_ea_len;
        TALLOC_CTX *mem_ctx = talloc_tos();
        struct ea_list *ea_list;
-       NTSTATUS status = get_ea_list_from_file_path(mem_ctx, conn, fsp, fname, &total_ea_len, &ea_list);
+       NTSTATUS status = get_ea_list_from_file_path(mem_ctx,
+                                       conn,
+                                       fsp,
+                                       smb_fname,
+                                       &total_ea_len,
+                                       &ea_list);
        if (!NT_STATUS_IS_OK(status)) {
                return;
        }
@@ -616,12 +692,16 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                const struct smb_filename *smb_fname, struct ea_list *ea_list)
 {
        NTSTATUS status;
-       char *fname = NULL;
 
        if (!lp_ea_support(SNUM(conn))) {
                return NT_STATUS_EAS_NOT_SUPPORTED;
        }
 
+       status = refuse_symlink(conn, fsp, smb_fname->base_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -641,8 +721,6 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                return STATUS_INVALID_EA_NAME;
        }
 
-       fname = smb_fname->base_name;
-
        for (;ea_list; ea_list = ea_list->next) {
                int ret;
                fstring unix_ea_name;
@@ -650,7 +728,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
                fstrcat(unix_ea_name, ea_list->ea.name);
 
-               canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+               canonicalize_ea_name(conn,
+                               fsp,
+                               smb_fname,
+                               unix_ea_name);
 
                DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
 
@@ -668,8 +749,10 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                                ret = SMB_VFS_FREMOVEXATTR(fsp, unix_ea_name);
                        } else {
                                DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
-                                       unix_ea_name, fname));
-                               ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
+                                       unix_ea_name, smb_fname->base_name));
+                               ret = SMB_VFS_REMOVEXATTR(conn,
+                                               smb_fname->base_name,
+                                               unix_ea_name);
                        }
 #ifdef ENOATTR
                        /* Removing a non existent attribute always succeeds. */
@@ -688,9 +771,13 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
                                                        ea_list->ea.value.data, ea_list->ea.value.length, 0);
                        } else {
                                DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
-                                       unix_ea_name, fname));
-                               ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
-                                                       ea_list->ea.value.data, ea_list->ea.value.length, 0);
+                                       unix_ea_name, smb_fname->base_name));
+                               ret = SMB_VFS_SETXATTR(conn,
+                                               smb_fname->base_name,
+                                               unix_ea_name,
+                                               ea_list->ea.value.data,
+                                               ea_list->ea.value.length,
+                                               0);
                        }
                }
 
@@ -741,74 +828,13 @@ static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, siz
                }
 
                offset += (namelen + 1); /* Go past the name + terminating zero. */
-               DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+               DLIST_ADD_END(ea_list_head, eal);
                DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
        }
 
        return ea_list_head;
 }
 
-/****************************************************************************
- Read one EA list entry from the buffer.
-****************************************************************************/
-
-struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
-{
-       struct ea_list *eal = talloc_zero(ctx, struct ea_list);
-       uint16 val_len;
-       unsigned int namelen;
-       size_t converted_size;
-
-       if (!eal) {
-               return NULL;
-       }
-
-       if (data_size < 6) {
-               return NULL;
-       }
-
-       eal->ea.flags = CVAL(pdata,0);
-       namelen = CVAL(pdata,1);
-       val_len = SVAL(pdata,2);
-
-       if (4 + namelen + 1 + val_len > data_size) {
-               return NULL;
-       }
-
-       /* Ensure the name is null terminated. */
-       if (pdata[namelen + 4] != '\0') {
-               return NULL;
-       }
-       if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) {
-               DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s",
-                        strerror(errno)));
-       }
-       if (!eal->ea.name) {
-               return NULL;
-       }
-
-       eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
-       if (!eal->ea.value.data) {
-               return NULL;
-       }
-
-       memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
-
-       /* Ensure we're null terminated just in case we print the value. */
-       eal->ea.value.data[val_len] = '\0';
-       /* But don't count the null. */
-       eal->ea.value.length--;
-
-       if (pbytes_used) {
-               *pbytes_used = 4 + namelen + 1 + val_len;
-       }
-
-       DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
-       dump_data(10, eal->ea.value.data, eal->ea.value.length);
-
-       return eal;
-}
-
 /****************************************************************************
  Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
 ****************************************************************************/
@@ -826,7 +852,7 @@ static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t d
                        return NULL;
                }
 
-               DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
+               DLIST_ADD_END(ea_list_head, eal);
                offset += bytes_used;
        }
 
@@ -918,8 +944,8 @@ void send_trans2_replies(connection_struct *conn,
        int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
        int data_alignment_offset = 0;
        bool overflow = False;
-       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;
 
        /* Modify the data_to_send and datasize and set the error if
           we're trying to send more than max_data_bytes. We still send
@@ -946,7 +972,7 @@ void send_trans2_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),
@@ -1086,7 +1112,7 @@ void send_trans2_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),
@@ -1126,7 +1152,7 @@ static void call_trans2open(connection_struct *conn,
        char *params = *pparams;
        char *pdata = *ppdata;
        int deny_mode;
-       int32 open_attr;
+       int32_t open_attr;
        bool oplock_request;
 #if 0
        bool return_additional_info;
@@ -1134,7 +1160,7 @@ static void call_trans2open(connection_struct *conn,
        time_t open_time;
 #endif
        int open_ofun;
-       uint32 open_size;
+       uint32_t open_size;
        char *pname;
        char *fname = NULL;
        off_t size=0;
@@ -1143,13 +1169,14 @@ static void call_trans2open(connection_struct *conn,
        int smb_action = 0;
        files_struct *fsp;
        struct ea_list *ea_list = NULL;
-       uint16 flags = 0;
+       uint16_t flags = 0;
        NTSTATUS status;
-       uint32 access_mask;
-       uint32 share_mode;
-       uint32 create_disposition;
-       uint32 create_options = 0;
+       uint32_t access_mask;
+       uint32_t share_mode;
+       uint32_t create_disposition;
+       uint32_t create_options = 0;
        uint32_t private_flags = 0;
+       uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
 
        /*
@@ -1183,9 +1210,25 @@ static void call_trans2open(connection_struct *conn,
                goto out;
        }
 
-       srvstr_get_path(ctx, params, req->flags2, &fname, pname,
-                       total_params - 28, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       pname,
+                       total_params - 28,
+                       STR_TERMINATE,
+                       &status);
+       } else {
+               srvstr_get_path(ctx,
+                       params,
+                       req->flags2,
+                       &fname,
+                       pname,
+                       total_params - 28,
+                       STR_TERMINATE,
                        &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                goto out;
@@ -1199,7 +1242,7 @@ static void call_trans2open(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
-                               0,
+                               ucf_flags,
                                NULL,
                                &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1280,15 +1323,17 @@ static void call_trans2open(connection_struct *conn,
                create_options,                         /* create_options */
                open_attr,                              /* file_attributes */
                oplock_request,                         /* oplock_request */
+               NULL,                                   /* lease */
                open_size,                              /* allocation_size */
                private_flags,
                NULL,                                   /* sd */
                ea_list,                                /* ea_list */
                &fsp,                                   /* result */
-               &smb_action);                           /* psbuf */
+               &smb_action,                            /* psbuf */
+               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. */
                        goto out;
                }
@@ -1317,7 +1362,7 @@ static void call_trans2open(connection_struct *conn,
        SSVAL(params,0,fsp->fnum);
        SSVAL(params,2,fattr);
        srv_put_dos_date2(params,4, mtime);
-       SIVAL(params,8, (uint32)size);
+       SIVAL(params,8, (uint32_t)size);
        SSVAL(params,12,deny_mode);
        SSVAL(params,14,0); /* open_type - file or directory. */
        SSVAL(params,16,0); /* open_state - only valid for IPC device. */
@@ -1334,7 +1379,7 @@ static void call_trans2open(connection_struct *conn,
        SIVAL(params,20,inode);
        SSVAL(params,24,0); /* Padding. */
        if (flags & 8) {
-               uint32 ea_size = estimate_ea_size(conn, fsp,
+               uint32_t ea_size = estimate_ea_size(conn, fsp,
                                                  smb_fname);
                SIVAL(params, 26, ea_size);
        } else {
@@ -1378,7 +1423,7 @@ static bool exact_match(bool has_wild,
  Return the filetype for UNIX extensions.
 ****************************************************************************/
 
-static uint32 unix_filetype(mode_t mode)
+static uint32_t unix_filetype(mode_t mode)
 {
        if(S_ISREG(mode))
                return UNIX_TYPE_FILE;
@@ -1417,7 +1462,7 @@ enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_
 
 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
                                const SMB_STRUCT_STAT *psbuf,
-                               uint32 perms,
+                               uint32_t perms,
                                enum perm_type ptype,
                                mode_t *ret_perms)
 {
@@ -1451,20 +1496,22 @@ static NTSTATUS unix_perms_from_wire( connection_struct *conn,
        ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
 #endif
 
-       switch (ptype) {
-       case PERM_NEW_FILE:
-       case PERM_EXISTING_FILE:
-               /* Apply mode mask */
+       if (ptype == PERM_NEW_FILE) {
+               /*
+                * "create mask"/"force create mode" are
+                * only applied to new files, not existing ones.
+                */
                ret &= lp_create_mask(SNUM(conn));
                /* Add in force bits */
                ret |= lp_force_create_mode(SNUM(conn));
-               break;
-       case PERM_NEW_DIR:
-       case PERM_EXISTING_DIR:
-               ret &= lp_dir_mask(SNUM(conn));
+       } else if (ptype == PERM_NEW_DIR) {
+               /*
+                * "directory mask"/"force directory mode" are
+                * only applied to new directories, not existing ones.
+                */
+               ret &= lp_directory_mask(SNUM(conn));
                /* Add in force bits */
-               ret |= lp_force_dir_mode(SNUM(conn));
-               break;
+               ret |= lp_force_directory_mode(SNUM(conn));
        }
 
        *ret_perms = ret;
@@ -1524,6 +1571,31 @@ static bool smbd_dirptr_lanman2_match_fn(TALLOC_CTX *ctx,
 
        /* Mangle fname if it's an illegal name. */
        if (mangle_must_mangle(dname, state->conn->params)) {
+               /*
+                * Slow path - ensure we can push the original name as UCS2. If
+                * not, then just don't return this name.
+                */
+               NTSTATUS status;
+               size_t ret_len = 0;
+               size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
+               uint8_t *tmp = talloc_array(talloc_tos(),
+                                       uint8_t,
+                                       len);
+
+               status = srvstr_push(NULL,
+                       FLAGS2_UNICODE_STRINGS,
+                       tmp,
+                       dname,
+                       len,
+                       STR_TERMINATE,
+                       &ret_len);
+
+               TALLOC_FREE(tmp);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       return false;
+               }
+
                ok = name_to_8_3(dname, mangled_name,
                                 true, state->conn->params);
                if (!ok) {
@@ -1625,7 +1697,7 @@ static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
        return true;
 }
 
-static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
+static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                    connection_struct *conn,
                                    uint16_t flags2,
                                    uint32_t info_level,
@@ -1641,7 +1713,6 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                    char *base_data,
                                    char **ppdata,
                                    char *end_data,
-                                   bool *out_of_space,
                                    uint64_t *last_entry_off)
 {
        char *p, *q, *pdata = *ppdata;
@@ -1649,27 +1720,32 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        uint64_t file_size = 0;
        uint64_t allocation_size = 0;
        uint64_t file_index = 0;
-       uint32_t len;
-       struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
+       size_t len = 0;
+       struct timespec mdate_ts = {0};
+       struct timespec adate_ts = {0};
+       struct timespec cdate_ts = {0};
+       struct timespec create_date_ts = {0};
        time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
        char *nameptr;
        char *last_entry_ptr;
        bool was_8_3;
        int off;
        int pad = 0;
-
-       *out_of_space = false;
-
-       ZERO_STRUCT(mdate_ts);
-       ZERO_STRUCT(adate_ts);
-       ZERO_STRUCT(create_date_ts);
-       ZERO_STRUCT(cdate_ts);
+       NTSTATUS status;
+       struct readdir_attr_data *readdir_attr_data = NULL;
 
        if (!(mode & FILE_ATTRIBUTE_DIRECTORY)) {
                file_size = get_file_size_stat(&smb_fname->st);
        }
        allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
 
+       status = SMB_VFS_READDIR_ATTR(conn, smb_fname, ctx, &readdir_attr_data);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (!NT_STATUS_EQUAL(NT_STATUS_NOT_SUPPORTED, status)) {
+                       return status;
+               }
+       }
+
        file_index = get_FileIndex(conn, &smb_fname->st);
 
        mdate_ts = smb_fname->st.st_ex_mtime;
@@ -1696,12 +1772,11 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        pad -= off;
 
        if (pad && pad > space_remaining) {
-               *out_of_space = true;
                DEBUG(9,("smbd_marshall_dir_entry: out of space "
                        "for padding (wanted %u, had %d)\n",
                        (unsigned int)pad,
                        space_remaining ));
-               return false; /* Not finished - just out of space */
+               return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
        }
 
        off += pad;
@@ -1731,17 +1806,20 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                srv_put_dos_date2(p,0,create_date);
                srv_put_dos_date2(p,4,adate);
                srv_put_dos_date2(p,8,mdate);
-               SIVAL(p,12,(uint32)file_size);
-               SIVAL(p,16,(uint32)allocation_size);
+               SIVAL(p,12,(uint32_t)file_size);
+               SIVAL(p,16,(uint32_t)allocation_size);
                SSVAL(p,20,mode);
                p += 23;
                nameptr = p;
                if (flags2 & FLAGS2_UNICODE_STRINGS) {
                        p += ucs2_align(base_data, p, 0);
                }
-               len = srvstr_push(base_data, flags2, p,
+               status = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE);
+                                 STR_TERMINATE, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                if (flags2 & FLAGS2_UNICODE_STRINGS) {
                        if (len > 2) {
                                SCVAL(nameptr, -1, len - 2);
@@ -1767,8 +1845,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                srv_put_dos_date2(p,0,create_date);
                srv_put_dos_date2(p,4,adate);
                srv_put_dos_date2(p,8,mdate);
-               SIVAL(p,12,(uint32)file_size);
-               SIVAL(p,16,(uint32)allocation_size);
+               SIVAL(p,12,(uint32_t)file_size);
+               SIVAL(p,16,(uint32_t)allocation_size);
                SSVAL(p,20,mode);
                {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
@@ -1777,9 +1855,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                }
                p += 27;
                nameptr = p - 1;
-               len = srvstr_push(base_data, flags2,
+               status = srvstr_push(base_data, flags2,
                                  p, fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE | STR_NOALIGN);
+                                 STR_TERMINATE | STR_NOALIGN, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                if (flags2 & FLAGS2_UNICODE_STRINGS) {
                        if (len > 2) {
                                len -= 2;
@@ -1802,11 +1883,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        {
                struct ea_list *file_list = NULL;
                size_t ea_len = 0;
-               NTSTATUS status;
 
                DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_EA_LIST\n"));
                if (!name_list) {
-                       return false;
+                       return NT_STATUS_INVALID_PARAMETER;
                }
                if (requires_resume_key) {
                        SIVAL(p,0,reskey);
@@ -1815,8 +1895,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                srv_put_dos_date2(p,0,create_date);
                srv_put_dos_date2(p,4,adate);
                srv_put_dos_date2(p,8,mdate);
-               SIVAL(p,12,(uint32)file_size);
-               SIVAL(p,16,(uint32)allocation_size);
+               SIVAL(p,12,(uint32_t)file_size);
+               SIVAL(p,16,(uint32_t)allocation_size);
                SSVAL(p,20,mode);
                p += 22; /* p now points to the EA area. */
 
@@ -1831,20 +1911,22 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                /* We need to determine if this entry will fit in the space available. */
                /* Max string size is 255 bytes. */
                if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
-                       *out_of_space = true;
                        DEBUG(9,("smbd_marshall_dir_entry: out of space "
                                "(wanted %u, had %d)\n",
                                (unsigned int)PTR_DIFF(p + 255 + ea_len,pdata),
                                space_remaining ));
-                       return False; /* Not finished - just out of space */
+                       return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
                }
 
                /* Push the ea_data followed by the name. */
                p += fill_ea_buffer(ctx, p, space_remaining, conn, name_list);
                nameptr = p;
-               len = srvstr_push(base_data, flags2,
+               status = srvstr_push(base_data, flags2,
                                  p + 1, fname, PTR_DIFF(end_data, p+1),
-                                 STR_TERMINATE | STR_NOALIGN);
+                                 STR_TERMINATE | STR_NOALIGN, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                if (flags2 & FLAGS2_UNICODE_STRINGS) {
                        if (len > 2) {
                                len -= 2;
@@ -1877,12 +1959,14 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length. */
-               {
+               if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
+                       SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+               } else {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
                                                                smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
-                       p += 4;
                }
+               p += 4;
                /* Clear the short name buffer. This is
                 * IMPORTANT as not doing so will trigger
                 * a Win2k client bug. JRA.
@@ -1895,9 +1979,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                memset(mangled_name,'\0',12);
                        }
                        mangled_name[12] = 0;
-                       len = srvstr_push(base_data, flags2,
+                       status = srvstr_push(base_data, flags2,
                                          p+2, mangled_name, 24,
-                                         STR_UPPER|STR_UNICODE);
+                                         STR_UPPER|STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        if (len < 24) {
                                memset(p + 2 + len,'\0',24 - len);
                        }
@@ -1906,9 +1993,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                        memset(p,'\0',26);
                }
                p += 2 + 24;
-               len = srvstr_push(base_data, flags2, p,
+               status = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE_ASCII);
+                                 STR_TERMINATE_ASCII, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                SIVAL(q,0,len);
                p += len;
 
@@ -1942,9 +2032,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,mode); p += 4;
-               len = srvstr_push(base_data, flags2,
+               status = srvstr_push(base_data, flags2,
                                  p + 4, fname, PTR_DIFF(end_data, p+4),
-                                 STR_TERMINATE_ASCII);
+                                 STR_TERMINATE_ASCII, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                SIVAL(p,0,len);
                p += 4 + len;
 
@@ -1985,9 +2078,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                        SIVAL(p,0,ea_size); /* Extended attributes */
                        p +=4;
                }
-               len = srvstr_push(base_data, flags2, p,
+               status = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE_ASCII);
+                                 STR_TERMINATE_ASCII, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                SIVAL(q, 0, len);
                p += len;
 
@@ -2017,9 +2113,12 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                p += 4;
                /* this must *not* be null terminated or w2k gets in a loop trying to set an
                   acl on a dir (tridge) */
-               len = srvstr_push(base_data, flags2, p,
+               status = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE_ASCII);
+                                 STR_TERMINATE_ASCII, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                SIVAL(p, -4, len);
                p += len;
 
@@ -2054,17 +2153,22 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length. */
-               {
+               if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
+                       SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+               } else {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
                                                                smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
-                       p +=4;
                }
+               p += 4;
                SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
                SBVAL(p,0,file_index); p += 8;
-               len = srvstr_push(base_data, flags2, p,
+               status = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE_ASCII);
+                                 STR_TERMINATE_ASCII, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                SIVAL(q, 0, len);
                p += len;
 
@@ -2100,17 +2204,43 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,mode); p += 4;
                q = p; p += 4; /* q is placeholder for name length */
-               {
+               if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
+                       SIVAL(p, 0, IO_REPARSE_TAG_DFS);
+               } else if (readdir_attr_data &&
+                          readdir_attr_data->type == RDATTR_AAPL) {
+                       /*
+                        * OS X specific SMB2 extension negotiated via
+                        * AAPL create context: return max_access in
+                        * ea_size field.
+                        */
+                       SIVAL(p, 0, readdir_attr_data->attr_data.aapl.max_access);
+               } else {
                        unsigned int ea_size = estimate_ea_size(conn, NULL,
                                                                smb_fname);
                        SIVAL(p,0,ea_size); /* Extended attributes */
-                       p +=4;
                }
-               /* Clear the short name buffer. This is
-                * IMPORTANT as not doing so will trigger
-                * a Win2k client bug. JRA.
-                */
-               if (!was_8_3 && check_mangled_names) {
+               p += 4;
+
+               if (readdir_attr_data &&
+                   readdir_attr_data->type == RDATTR_AAPL) {
+                       /*
+                        * OS X specific SMB2 extension negotiated via
+                        * AAPL create context: return resource fork
+                        * length and compressed FinderInfo in
+                        * shortname field.
+                        *
+                        * According to documentation short_name_len
+                        * should be 0, but on the wire behaviour
+                        * shows its set to 24 by clients.
+                        */
+                       SSVAL(p, 0, 24);
+
+                       /* Resourefork length */
+                       SBVAL(p, 2, readdir_attr_data->attr_data.aapl.rfork_size);
+
+                       /* Compressed FinderInfo */
+                       memcpy(p + 10, &readdir_attr_data->attr_data.aapl.finder_info, 16);
+               } else if (!was_8_3 && check_mangled_names) {
                        char mangled_name[13]; /* mangled 8.3 name. */
                        if (!name_to_8_3(fname,mangled_name,True,
                                        conn->params)) {
@@ -2118,23 +2248,48 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                memset(mangled_name,'\0',12);
                        }
                        mangled_name[12] = 0;
-                       len = srvstr_push(base_data, flags2,
+                       status = srvstr_push(base_data, flags2,
                                          p+2, mangled_name, 24,
-                                         STR_UPPER|STR_UNICODE);
+                                         STR_UPPER|STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SSVAL(p, 0, len);
                        if (len < 24) {
                                memset(p + 2 + len,'\0',24 - len);
                        }
                        SSVAL(p, 0, len);
                } else {
+                       /* Clear the short name buffer. This is
+                        * IMPORTANT as not doing so will trigger
+                        * a Win2k client bug. JRA.
+                        */
                        memset(p,'\0',26);
                }
                p += 26;
-               SSVAL(p,0,0); p += 2; /* Reserved ? */
+
+               /* Reserved ? */
+               if (readdir_attr_data &&
+                   readdir_attr_data->type == RDATTR_AAPL) {
+                       /*
+                        * OS X specific SMB2 extension negotiated via
+                        * AAPL create context: return UNIX mode in
+                        * reserved field.
+                        */
+                       uint16_t aapl_mode = (uint16_t)readdir_attr_data->attr_data.aapl.unix_mode;
+                       SSVAL(p, 0, aapl_mode);
+               } else {
+                       SSVAL(p, 0, 0);
+               }
+               p += 2;
+
                SBVAL(p,0,file_index); p += 8;
-               len = srvstr_push(base_data, flags2, p,
+               status = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
-                                 STR_TERMINATE_ASCII);
+                                 STR_TERMINATE_ASCII, &len);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
                SIVAL(q,0,len);
                p += len;
 
@@ -2170,17 +2325,23 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                        DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX\n"));
                        p = store_file_unix_basic(conn, p,
                                                NULL, &smb_fname->st);
-                       len = srvstr_push(base_data, flags2, p,
+                       status = srvstr_push(base_data, flags2, p,
                                          fname, PTR_DIFF(end_data, p),
-                                         STR_TERMINATE);
+                                         STR_TERMINATE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                } else {
                        DEBUG(10,("smbd_marshall_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
                        p = store_file_unix_basic_info2(conn, p,
                                                NULL, &smb_fname->st);
                        nameptr = p;
                        p += 4;
-                       len = srvstr_push(base_data, flags2, p, fname,
-                                         PTR_DIFF(end_data, p), 0);
+                       status = srvstr_push(base_data, flags2, p, fname,
+                                         PTR_DIFF(end_data, p), 0, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SIVAL(nameptr, 0, len);
                }
 
@@ -2208,16 +2369,15 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                break;
 
        default:
-               return false;
+               return NT_STATUS_INVALID_LEVEL;
        }
 
        if (PTR_DIFF(p,pdata) > space_remaining) {
-               *out_of_space = true;
                DEBUG(9,("smbd_marshall_dir_entry: out of space "
                        "(wanted %u, had %d)\n",
                        (unsigned int)PTR_DIFF(p,pdata),
                        space_remaining ));
-               return false; /* Not finished - just out of space */
+               return STATUS_MORE_ENTRIES; /* Not finished - just out of space */
        }
 
        /* Setup the last entry pointer, as an offset from base_data */
@@ -2225,15 +2385,15 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        /* Advance the data pointer to the next slot */
        *ppdata = p;
 
-       return true;
+       return NT_STATUS_OK;
 }
 
-bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
+NTSTATUS smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
                               connection_struct *conn,
                               struct dptr_struct *dirptr,
-                              uint16 flags2,
+                              uint16_t flags2,
                               const char *path_mask,
-                              uint32 dirtype,
+                              uint32_t dirtype,
                               int info_level,
                               int requires_resume_key,
                               bool dont_descend,
@@ -2244,7 +2404,6 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
                               char *base_data,
                               char *end_data,
                               int space_remaining,
-                              bool *out_of_space,
                               bool *got_exact_match,
                               int *_last_entry_off,
                               struct ea_list *name_list)
@@ -2258,15 +2417,15 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
        struct smbd_dirptr_lanman2_state state;
        bool ok;
        uint64_t last_entry_off = 0;
+       NTSTATUS status;
 
        ZERO_STRUCT(state);
        state.conn = conn;
        state.info_level = info_level;
-       state.check_mangled_names = lp_manglednames(conn->params);
+       state.check_mangled_names = lp_mangled_names(conn->params);
        state.has_wild = dptr_has_wild(dirptr);
        state.got_exact_match = false;
 
-       *out_of_space = false;
        *got_exact_match = false;
 
        p = strrchr_m(path_mask,'/');
@@ -2294,12 +2453,12 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
                                   &mode,
                                   &prev_dirpos);
        if (!ok) {
-               return false;
+               return NT_STATUS_END_OF_FILE;
        }
 
        *got_exact_match = state.got_exact_match;
 
-       ok = smbd_marshall_dir_entry(ctx,
+       status = smbd_marshall_dir_entry(ctx,
                                     conn,
                                     flags2,
                                     info_level,
@@ -2315,28 +2474,31 @@ bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
                                     base_data,
                                     ppdata,
                                     end_data,
-                                    out_of_space,
                                     &last_entry_off);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_ILLEGAL_CHARACTER)) {
+               DEBUG(1,("Conversion error: illegal character: %s\n",
+                        smb_fname_str_dbg(smb_fname)));
+       }
        TALLOC_FREE(fname);
        TALLOC_FREE(smb_fname);
-       if (*out_of_space) {
+       if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
                dptr_SeekDir(dirptr, prev_dirpos);
-               return false;
+               return status;
        }
-       if (!ok) {
-               return false;
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        *_last_entry_off = last_entry_off;
-       return true;
+       return NT_STATUS_OK;
 }
 
-static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
+static NTSTATUS get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                connection_struct *conn,
                                struct dptr_struct *dirptr,
-                               uint16 flags2,
+                               uint16_t flags2,
                                const char *path_mask,
-                               uint32 dirtype,
+                               uint32_t dirtype,
                                int info_level,
                                bool requires_resume_key,
                                bool dont_descend,
@@ -2345,7 +2507,6 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                char *base_data,
                                char *end_data,
                                int space_remaining,
-                               bool *out_of_space,
                                bool *got_exact_match,
                                int *last_entry_off,
                                struct ea_list *name_list)
@@ -2364,7 +2525,7 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                         align, do_pad,
                                         ppdata, base_data, end_data,
                                         space_remaining,
-                                        out_of_space, got_exact_match,
+                                        got_exact_match,
                                         last_entry_off, name_list);
 }
 
@@ -2387,9 +2548,9 @@ static void call_trans2findfirst(connection_struct *conn,
        char *params = *pparams;
        char *pdata = *ppdata;
        char *data_end;
-       uint32 dirtype;
+       uint32_t dirtype;
        int maxentries;
-       uint16 findfirst_flags;
+       uint16_t findfirst_flags;
        bool close_after_first;
        bool close_if_end;
        bool requires_resume_key;
@@ -2409,11 +2570,12 @@ static void call_trans2findfirst(connection_struct *conn,
        struct ea_list *ea_list = NULL;
        NTSTATUS ntstatus = NT_STATUS_OK;
        bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
-       TALLOC_CTX *ctx = talloc_tos();
        struct dptr_struct *dirptr = NULL;
        struct smbd_server_connection *sconn = req->sconn;
-       uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP);
+       uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        bool backup_priv = false;
+       bool as_root = false;
 
        if (total_params < 13) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2469,9 +2631,27 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                        goto out;
        }
 
-       srvstr_get_path_wcard(ctx, params, req->flags2, &directory,
-                             params+12, total_params - 12,
-                             STR_TERMINATE, &ntstatus, &mask_contains_wcard);
+       if (req->posix_pathnames) {
+               srvstr_get_path_wcard_posix(talloc_tos(),
+                               params,
+                               req->flags2,
+                               &directory,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+       } else {
+               srvstr_get_path_wcard(talloc_tos(),
+                               params,
+                               req->flags2,
+                               &directory,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+       }
        if (!NT_STATUS_IS_OK(ntstatus)) {
                reply_nterror(req, ntstatus);
                goto out;
@@ -2479,7 +2659,8 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
 
        if (backup_priv) {
                become_root();
-               ntstatus = filename_convert_with_privilege(ctx,
+               as_root = true;
+               ntstatus = filename_convert_with_privilege(talloc_tos(),
                                conn,
                                req,
                                directory,
@@ -2487,7 +2668,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                                &mask_contains_wcard,
                                &smb_dname);
        } else {
-               ntstatus = filename_convert(ctx, conn,
+               ntstatus = filename_convert(talloc_tos(), conn,
                                    req->flags2 & FLAGS2_DFS_PATHNAMES,
                                    directory,
                                    ucf_flags,
@@ -2513,7 +2694,7 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
        if(p == NULL) {
                /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
                if((directory[0] == '.') && (directory[1] == '\0')) {
-                       mask = talloc_strdup(ctx,"*");
+                       mask = talloc_strdup(talloc_tos(),"*");
                        if (!mask) {
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
                                goto out;
@@ -2531,12 +2712,14 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                        reply_nterror(req, NT_STATUS_NO_MEMORY);
                        goto out;
                }
+               /* Ensure smb_dname->base_name matches. */
+               smb_dname->base_name = directory;
        }
 
        DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
 
        if (info_level == SMB_FIND_EA_LIST) {
-               uint32 ea_size;
+               uint32_t ea_size;
 
                if (total_data < 4) {
                        reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2557,13 +2740,18 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
 
                /* Pull out the list of names. */
-               ea_list = read_ea_name_list(ctx, pdata + 4, ea_size - 4);
+               ea_list = read_ea_name_list(talloc_tos(), pdata + 4, ea_size - 4);
                if (!ea_list) {
                        reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                        goto out;
                }
        }
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               goto out;
+       }
+
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if(*ppdata == NULL ) {
@@ -2572,7 +2760,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        }
        pdata = *ppdata;
        data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
-
+       /*
+        * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
+        * error.
+        */
+       memset(pdata + total_data, 0, ((max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data));
        /* Realloc the params space */
        *pparams = (char *)SMB_REALLOC(*pparams, 10);
        if (*pparams == NULL) {
@@ -2587,7 +2779,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        ntstatus = dptr_create(conn,
                                req,
                                NULL, /* fsp */
-                               directory,
+                               smb_dname,
                                False,
                                True,
                                req->smbpid,
@@ -2617,9 +2809,12 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                a different TRANS2 call. */
 
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-                directory,lp_dontdescend(ctx, SNUM(conn))));
-       if (in_list(directory,lp_dontdescend(ctx, SNUM(conn)),conn->case_sensitive))
+                directory,lp_dont_descend(talloc_tos(), SNUM(conn))));
+       if (in_list(directory,
+                       lp_dont_descend(talloc_tos(), SNUM(conn)),
+                       conn->case_sensitive)) {
                dont_descend = True;
+       }
 
        p = pdata;
        space_remaining = max_data_bytes;
@@ -2634,7 +2829,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        out_of_space = True;
                        finished = False;
                } else {
-                       finished = !get_lanman2_dir_entry(ctx,
+                       ntstatus = get_lanman2_dir_entry(talloc_tos(),
                                        conn,
                                        dirptr,
                                        req->flags2,
@@ -2642,14 +2837,24 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                                        requires_resume_key,dont_descend,
                                        ask_sharemode,
                                        &p,pdata,data_end,
-                                       space_remaining, &out_of_space,
+                                       space_remaining,
                                        &got_exact_match,
                                        &last_entry_off, ea_list);
+                       if (NT_STATUS_EQUAL(ntstatus,
+                                       NT_STATUS_ILLEGAL_CHARACTER)) {
+                               /*
+                                * Bad character conversion on name. Ignore this
+                                * entry.
+                                */
+                               continue;
+                       }
+                       if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
+                               out_of_space = true;
+                       } else {
+                               finished = !NT_STATUS_IS_OK(ntstatus);
+                       }
                }
 
-               if (finished && out_of_space)
-                       finished = False;
-
                if (!finished && !out_of_space)
                        numentries++;
 
@@ -2734,7 +2939,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        }
  out:
 
-       if (backup_priv) {
+       if (as_root) {
                unbecome_root();
        }
 
@@ -2762,9 +2967,9 @@ static void call_trans2findnext(connection_struct *conn,
        char *data_end;
        int dptr_num;
        int maxentries;
-       uint16 info_level;
-       uint32 resume_key;
-       uint16 findnext_flags;
+       uint16_t info_level;
+       uint32_t resume_key;
+       uint16_t findnext_flags;
        bool close_after_request;
        bool close_if_end;
        bool requires_resume_key;
@@ -2774,7 +2979,7 @@ static void call_trans2findnext(connection_struct *conn,
        const char *mask = NULL;
        const char *directory = NULL;
        char *p = NULL;
-       uint16 dirtype;
+       uint16_t dirtype;
        int numentries = 0;
        int i, last_entry_off=0;
        bool finished = False;
@@ -2788,6 +2993,7 @@ static void call_trans2findnext(connection_struct *conn,
        struct dptr_struct *dirptr;
        struct smbd_server_connection *sconn = req->sconn;
        bool backup_priv = false; 
+       bool as_root = false;
 
        if (total_params < 13) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2806,10 +3012,27 @@ static void call_trans2findnext(connection_struct *conn,
 
        if (!continue_bit) {
                /* We only need resume_name if continue_bit is zero. */
-               srvstr_get_path_wcard(ctx, params, req->flags2, &resume_name,
-                             params+12,
-                             total_params - 12, STR_TERMINATE, &ntstatus,
-                             &mask_contains_wcard);
+               if (req->posix_pathnames) {
+                       srvstr_get_path_wcard_posix(ctx,
+                               params,
+                               req->flags2,
+                               &resume_name,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+               } else {
+                       srvstr_get_path_wcard(ctx,
+                               params,
+                               req->flags2,
+                               &resume_name,
+                               params+12,
+                               total_params - 12,
+                               STR_TERMINATE,
+                               &ntstatus,
+                               &mask_contains_wcard);
+               }
                if (!NT_STATUS_IS_OK(ntstatus)) {
                        /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
                           complain (it thinks we're asking for the directory above the shared
@@ -2865,7 +3088,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
        }
 
        if (info_level == SMB_FIND_EA_LIST) {
-               uint32 ea_size;
+               uint32_t ea_size;
 
                if (total_data < 4) {
                        reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -2893,6 +3116,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                }
        }
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if(*ppdata == NULL) {
@@ -2903,6 +3131,11 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
        pdata = *ppdata;
        data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
 
+       /*
+        * squash valgrind "writev(vector[...]) points to uninitialised byte(s)"
+        * error.
+        */
+       memset(pdata + total_data, 0, (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN) - total_data);
        /* Realloc the params space */
        *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
        if(*pparams == NULL ) {
@@ -2946,8 +3179,8 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                a different TRANS2 call. */
 
        DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
-                directory,lp_dontdescend(ctx, SNUM(conn))));
-       if (in_list(directory,lp_dontdescend(ctx, SNUM(conn)),conn->case_sensitive))
+                directory,lp_dont_descend(ctx, SNUM(conn))));
+       if (in_list(directory,lp_dont_descend(ctx, SNUM(conn)),conn->case_sensitive))
                dont_descend = True;
 
        p = pdata;
@@ -2956,6 +3189,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 
        if (backup_priv) {
                become_root();
+               as_root = true;
        }
 
        /*
@@ -3005,7 +3239,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                        out_of_space = True;
                        finished = False;
                } else {
-                       finished = !get_lanman2_dir_entry(ctx,
+                       ntstatus = get_lanman2_dir_entry(ctx,
                                                conn,
                                                dirptr,
                                                req->flags2,
@@ -3013,14 +3247,24 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                                                requires_resume_key,dont_descend,
                                                ask_sharemode,
                                                &p,pdata,data_end,
-                                               space_remaining, &out_of_space,
+                                               space_remaining,
                                                &got_exact_match,
                                                &last_entry_off, ea_list);
+                       if (NT_STATUS_EQUAL(ntstatus,
+                                       NT_STATUS_ILLEGAL_CHARACTER)) {
+                               /*
+                                * Bad character conversion on name. Ignore this
+                                * entry.
+                                */
+                               continue;
+                       }
+                       if (NT_STATUS_EQUAL(ntstatus, STATUS_MORE_ENTRIES)) {
+                               out_of_space = true;
+                       } else {
+                               finished = !NT_STATUS_IS_OK(ntstatus);
+                       }
                }
 
-               if (finished && out_of_space)
-                       finished = False;
-
                if (!finished && !out_of_space)
                        numentries++;
 
@@ -3047,7 +3291,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                dptr_close(sconn, &dptr_num); /* This frees up the saved mask */
        }
 
-       if (backup_priv) {
+       if (as_root) {
                unbecome_root();
        }
 
@@ -3104,24 +3348,30 @@ static void samba_extended_info_version(struct smb_extended_info *extended_info)
                  "%s", samba_version_string());
 }
 
-NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
+NTSTATUS smbd_do_qfsinfo(struct smbXsrv_connection *xconn,
+                        connection_struct *conn,
                         TALLOC_CTX *mem_ctx,
                         uint16_t info_level,
                         uint16_t flags2,
                         unsigned int max_data_bytes,
+                        size_t *fixed_portion,
                         struct smb_filename *fname,
                         char **ppdata,
                         int *ret_data_len)
 {
        char *pdata, *end_data;
-       int data_len = 0, len;
+       int data_len = 0;
+       size_t len = 0;
        const char *vname = volume_label(talloc_tos(), SNUM(conn));
        int snum = SNUM(conn);
-       char *fstype = lp_fstype(talloc_tos(), SNUM(conn));
-       char *filename = NULL;
-       uint32 additional_flags = 0;
+       const char *fstype = lp_fstype(SNUM(conn));
+       const char *filename = NULL;
+       const uint64_t bytes_per_sector = 512;
+       uint32_t additional_flags = 0;
        struct smb_filename smb_fname;
        SMB_STRUCT_STAT st;
+       NTSTATUS status = NT_STATUS_OK;
+       uint64_t df_ret;
 
        if (fname == NULL || fname->base_name == NULL) {
                filename = ".";
@@ -3150,6 +3400,10 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
 
        st = smb_fname.st;
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        if (*ppdata == NULL) {
@@ -3160,12 +3414,16 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
        memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
        end_data = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
 
+       *fixed_portion = 0;
+
        switch (info_level) {
                case SMB_INFO_ALLOCATION:
                {
-                       uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
+                       uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
                        data_len = 18;
-                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
+                                               &dsize);
+                       if (df_ret == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
 
@@ -3182,7 +3440,6 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
                                dsize *= factor;
                                dfree *= factor;
                        }
-                       bytes_per_sector = 512;
                        sectors_per_unit = bsize/bytes_per_sector;
 
                        DEBUG(5,("smbd_do_qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
@@ -3210,16 +3467,19 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                         * this call so try fixing this by adding a terminating null to
                         * the pushed string. The change here was adding the STR_TERMINATE. JRA.
                         */
-                       len = srvstr_push(
+                       status = srvstr_push(
                                pdata, flags2,
                                pdata+l2_vol_szVolLabel, vname,
                                PTR_DIFF(end_data, pdata+l2_vol_szVolLabel),
-                               STR_NOALIGN|STR_TERMINATE);
+                               STR_NOALIGN|STR_TERMINATE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SCVAL(pdata,l2_vol_cch,len);
                        data_len = l2_vol_szVolLabel + len;
-                       DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %d, name = %s\n",
+                       DEBUG(5,("smbd_do_qfsinfo : time = %x, namelen = %u, name = %s\n",
                                 (unsigned)convert_timespec_to_time_t(st.st_ex_ctime),
-                                len, vname));
+                                (unsigned)len, vname));
                        break;
 
                case SMB_QUERY_FS_ATTRIBUTE_INFO:
@@ -3247,17 +3507,30 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                        SIVAL(pdata,4,255); /* Max filename component length */
                        /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
                                and will think we can't do long filenames */
-                       len = srvstr_push(pdata, flags2, pdata+12, fstype,
+                       status = srvstr_push(pdata, flags2, pdata+12, fstype,
                                          PTR_DIFF(end_data, pdata+12),
-                                         STR_UNICODE);
+                                         STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SIVAL(pdata,8,len);
                        data_len = 12 + len;
+                       if (max_data_bytes >= 16 && data_len > max_data_bytes) {
+                               /* the client only requested a portion of the
+                                  file system name */
+                               data_len = max_data_bytes;
+                               status = STATUS_BUFFER_OVERFLOW;
+                       }
+                       *fixed_portion = 16;
                        break;
 
                case SMB_QUERY_FS_LABEL_INFO:
                case SMB_FS_LABEL_INFORMATION:
-                       len = srvstr_push(pdata, flags2, pdata+4, vname,
-                                         PTR_DIFF(end_data, pdata+4), 0);
+                       status = srvstr_push(pdata, flags2, pdata+4, vname,
+                                         PTR_DIFF(end_data, pdata+4), 0, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        data_len = 4 + len;
                        SIVAL(pdata,0,len);
                        break;
@@ -3273,23 +3546,35 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                                (str_checksum(get_local_machine_name())<<16));
 
                        /* Max label len is 32 characters. */
-                       len = srvstr_push(pdata, flags2, pdata+18, vname,
+                       status = srvstr_push(pdata, flags2, pdata+18, vname,
                                          PTR_DIFF(end_data, pdata+18),
-                                         STR_UNICODE);
+                                         STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SIVAL(pdata,12,len);
                        data_len = 18+len;
 
                        DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n",
                                (int)strlen(vname),vname,
                                lp_servicename(talloc_tos(), snum)));
+                       if (max_data_bytes >= 24 && data_len > max_data_bytes) {
+                               /* the client only requested a portion of the
+                                  volume label */
+                               data_len = max_data_bytes;
+                               status = STATUS_BUFFER_OVERFLOW;
+                       }
+                       *fixed_portion = 24;
                        break;
 
                case SMB_QUERY_FS_SIZE_INFO:
                case SMB_FS_SIZE_INFORMATION:
                {
-                       uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
+                       uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
                        data_len = 24;
-                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
+                                               &dsize);
+                       if (df_ret == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
                        block_size = lp_block_size(snum);
@@ -3305,7 +3590,6 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                                dsize *= factor;
                                dfree *= factor;
                        }
-                       bytes_per_sector = 512;
                        sectors_per_unit = bsize/bytes_per_sector;
                        DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
@@ -3314,14 +3598,17 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        SBIG_UINT(pdata,8,dfree);
                        SIVAL(pdata,16,sectors_per_unit);
                        SIVAL(pdata,20,bytes_per_sector);
+                       *fixed_portion = 24;
                        break;
                }
 
                case SMB_FS_FULL_SIZE_INFORMATION:
                {
-                       uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
+                       uint64_t dfree,dsize,bsize,block_size,sectors_per_unit;
                        data_len = 32;
-                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       df_ret = get_dfree_info(conn, filename, &bsize, &dfree,
+                                               &dsize);
+                       if (df_ret == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
                        block_size = lp_block_size(snum);
@@ -3337,7 +3624,6 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                dsize *= factor;
                                dfree *= factor;
                        }
-                       bytes_per_sector = 512;
                        sectors_per_unit = bsize/bytes_per_sector;
                        DEBUG(5,("smbd_do_qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
@@ -3347,6 +3633,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
                        SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
                        SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
+                       *fixed_portion = 32;
                        break;
                }
 
@@ -3361,6 +3648,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        data_len = 8;
                        SIVAL(pdata,0,FILE_DEVICE_DISK); /* dev type */
                        SIVAL(pdata,4,characteristics);
+                       *fixed_portion = 8;
                        break;
                }
 
@@ -3400,7 +3688,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
 
                        /* access check */
                        if (get_current_uid(conn) != 0) {
-                               DEBUG(0,("set_user_quota: access_denied "
+                               DEBUG(0,("get_user_quota: access_denied "
                                         "service [%s] user [%s]\n",
                                         lp_servicename(talloc_tos(), SNUM(conn)),
                                         conn->session_info->unix_info->unix_name));
@@ -3453,6 +3741,34 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        break;
                }
 
+               case SMB_FS_SECTOR_SIZE_INFORMATION:
+               {
+                       data_len = 28;
+                       /*
+                        * These values match a physical Windows Server 2012
+                        * share backed by NTFS atop spinning rust.
+                        */
+                       DEBUG(5, ("SMB_FS_SECTOR_SIZE_INFORMATION:"));
+                       /* logical_bytes_per_sector */
+                       SIVAL(pdata, 0, bytes_per_sector);
+                       /* phys_bytes_per_sector_atomic */
+                       SIVAL(pdata, 4, bytes_per_sector);
+                       /* phys_bytes_per_sector_perf */
+                       SIVAL(pdata, 8, bytes_per_sector);
+                       /* fs_effective_phys_bytes_per_sector_atomic */
+                       SIVAL(pdata, 12, bytes_per_sector);
+                       /* flags */
+                       SIVAL(pdata, 16, SSINFO_FLAGS_ALIGNED_DEVICE
+                               | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE);
+                       /* byte_off_sector_align */
+                       SIVAL(pdata, 20, 0);
+                       /* byte_off_partition_align */
+                       SIVAL(pdata, 24, 0);
+                       *fixed_portion = 28;
+                       break;
+               }
+
+
                /*
                 * Query the version and capabilities of the CIFS UNIX extensions
                 * in use.
@@ -3461,8 +3777,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                case SMB_QUERY_CIFS_UNIX_INFO:
                {
                        bool large_write = lp_min_receive_file_size() &&
-                                       !srv_is_signing_active(conn->sconn);
-                       bool large_read = !srv_is_signing_active(conn->sconn);
+                                       !srv_is_signing_active(xconn);
+                       bool large_read = !srv_is_signing_active(xconn);
                        int encrypt_caps = 0;
 
                        if (!lp_unix_extensions()) {
@@ -3473,6 +3789,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        case SMB_SIGNING_OFF:
                                encrypt_caps = 0;
                                break;
+                       case SMB_SIGNING_DESIRED:
                        case SMB_SIGNING_IF_REQUIRED:
                        case SMB_SIGNING_DEFAULT:
                                encrypt_caps = CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP;
@@ -3629,7 +3946,8 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                        &conn->session_info->security_token->sids[i],
                                        0);
 
-                               sid_linearize(pdata + data_len, sid_len,
+                               sid_linearize((uint8_t *)(pdata + data_len),
+                                             sid_len,
                                    &conn->session_info->security_token->sids[i]);
                                data_len += sid_len;
                        }
@@ -3642,7 +3960,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                         * Thursby MAC extension... ONLY on NTFS filesystems
                         * once we do streams then we don't need this
                         */
-                       if (strequal(lp_fstype(talloc_tos(), SNUM(conn)),"NTFS")) {
+                       if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
                                data_len = 88;
                                SIVAL(pdata,84,0x100); /* Don't support mac... */
                                break;
@@ -3653,7 +3971,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
        }
 
        *ret_data_len = data_len;
-       return NT_STATUS_OK;
+       return status;
 }
 
 /****************************************************************************
@@ -3669,6 +3987,7 @@ static void call_trans2qfsinfo(connection_struct *conn,
        char *params = *pparams;
        uint16_t info_level;
        int data_len = 0;
+       size_t fixed_portion;
        NTSTATUS status;
 
        if (total_params < 2) {
@@ -3690,10 +4009,11 @@ static void call_trans2qfsinfo(connection_struct *conn,
 
        DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
 
-       status = smbd_do_qfsinfo(conn, req,
+       status = smbd_do_qfsinfo(req->xconn, conn, req,
                                 info_level,
                                 req->flags2,
                                 max_data_bytes,
+                                &fixed_portion,
                                 NULL,
                                 ppdata, &data_len);
        if (!NT_STATUS_IS_OK(status)) {
@@ -3720,10 +4040,10 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                 char **ppdata, int total_data,
                                 unsigned int max_data_bytes)
 {
-       struct smbd_server_connection *sconn = req->sconn;
+       struct smbXsrv_connection *xconn = req->xconn;
        char *pdata = *ppdata;
        char *params = *pparams;
-       uint16 info_level;
+       uint16_t info_level;
 
        DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",
                  lp_servicename(talloc_tos(), SNUM(conn))));
@@ -3777,31 +4097,31 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                        NT_STATUS_INVALID_PARAMETER);
                                return;
                        }
-                       sconn->smb1.unix_info.client_major = SVAL(pdata,0);
-                       sconn->smb1.unix_info.client_minor = SVAL(pdata,2);
-                       sconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
-                       sconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
+                       xconn->smb1.unix_info.client_major = SVAL(pdata,0);
+                       xconn->smb1.unix_info.client_minor = SVAL(pdata,2);
+                       xconn->smb1.unix_info.client_cap_low = IVAL(pdata,4);
+                       xconn->smb1.unix_info.client_cap_high = IVAL(pdata,8);
                        /* Just print these values for now. */
                        DEBUG(10, ("call_trans2setfsinfo: set unix_info info. "
                                   "major = %u, minor = %u cap_low = 0x%x, "
                                   "cap_high = 0x%xn",
-                                  (unsigned int)sconn->
+                                  (unsigned int)xconn->
                                   smb1.unix_info.client_major,
-                                  (unsigned int)sconn->
+                                  (unsigned int)xconn->
                                   smb1.unix_info.client_minor,
-                                  (unsigned int)sconn->
+                                  (unsigned int)xconn->
                                   smb1.unix_info.client_cap_low,
-                                  (unsigned int)sconn->
+                                  (unsigned int)xconn->
                                   smb1.unix_info.client_cap_high));
 
                        /* Here is where we must switch to posix pathname processing... */
-                       if (sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+                       if (xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
                                lp_set_posix_pathnames();
                                mangle_change_to_posix();
                        }
 
-                       if ((sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
-                           !(sconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
+                       if ((xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
+                           !(xconn->smb1.unix_info.client_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
                                /* Client that knows how to do posix locks,
                                 * but not posix open/mkdir operations. Set a
                                 * default type for read/write checks. */
@@ -3831,7 +4151,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                        return;
                                }
 
-                               if (req->sconn->smb1.echo_handler.trusted_fde) {
+                               if (xconn->smb1.echo_handler.trusted_fde) {
                                        DEBUG( 2,("call_trans2setfsinfo: "
                                                "request transport encryption disabled"
                                                "with 'fork echo handler = yes'\n"));
@@ -3895,7 +4215,7 @@ static void call_trans2setfsinfo(connection_struct *conn,
                                        return;
                                }
 
-                               /* note: normaly there're 48 bytes,
+                               /* note: normally there're 48 bytes,
                                 * but we didn't use the last 6 bytes for now 
                                 * --metze 
                                 */
@@ -4174,7 +4494,7 @@ static const struct {unsigned stat_fflag; unsigned smb_fflag;}
 };
 
 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
-                               uint32 *smb_fflags, uint32 *smb_fmask)
+                               uint32_t *smb_fflags, uint32_t *smb_fmask)
 {
        int i;
 
@@ -4187,11 +4507,11 @@ static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
 }
 
 static bool map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
-                               const uint32 smb_fflags,
-                               const uint32 smb_fmask,
+                               const uint32_t smb_fflags,
+                               const uint32_t smb_fmask,
                                int *stat_fflags)
 {
-       uint32 max_fmask = 0;
+       uint32_t max_fmask = 0;
        int i;
 
        *stat_fflags = psbuf->st_ex_flags;
@@ -4231,8 +4551,8 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
                                files_struct *fsp,
                                const SMB_STRUCT_STAT *psbuf)
 {
-       uint32 file_flags = 0;
-       uint32 flags_mask = 0;
+       uint32_t file_flags = 0;
+       uint32_t flags_mask = 0;
 
        pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
 
@@ -4257,6 +4577,10 @@ static NTSTATUS marshall_stream_info(unsigned int num_streams,
        unsigned int i;
        unsigned int ofs = 0;
 
+       if (max_data_bytes < 32) {
+               return NT_STATUS_INFO_LENGTH_MISMATCH;
+       }
+
        for (i = 0; i < num_streams; i++) {
                unsigned int next_offset;
                size_t namelen;
@@ -4340,7 +4664,7 @@ static void call_trans2qpipeinfo(connection_struct *conn,
        char *pdata = *ppdata;
        unsigned int data_size = 0;
        unsigned int param_size = 2;
-       uint16 info_level;
+       uint16_t info_level;
        files_struct *fsp;
 
        if (!params) {
@@ -4368,6 +4692,10 @@ static void call_trans2qpipeinfo(connection_struct *conn,
        }
        params = *pparams;
        SSVAL(params,0,0);
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
        *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); 
        if (*ppdata == NULL ) {
@@ -4408,6 +4736,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                               char *lock_data,
                               uint16_t flags2,
                               unsigned int max_data_bytes,
+                              size_t *fixed_portion,
                               char **ppdata,
                               unsigned int *pdata_size)
 {
@@ -4428,6 +4757,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
        uint64_t allocation_size = 0;
        uint64_t file_index = 0;
        uint32_t access_mask = 0;
+       size_t len = 0;
 
        if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
                return NT_STATUS_INVALID_LEVEL;
@@ -4449,6 +4779,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                nlink -= 1;
        }
 
+       if (max_data_bytes + DIR_ENTRY_SAFETY_MARGIN < max_data_bytes) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
        *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); 
        if (*ppdata == NULL) {
@@ -4544,6 +4878,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
           BasicFileInformationTest. -tpot */
        file_index = get_FileIndex(conn, psbuf);
 
+       *fixed_portion = 0;
+
        switch (info_level) {
                case SMB_INFO_STANDARD:
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_INFO_STANDARD\n"));
@@ -4551,8 +4887,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
                        srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
                        srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
-                       SIVAL(pdata,l1_cbFile,(uint32)file_size);
-                       SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
+                       SIVAL(pdata,l1_cbFile,(uint32_t)file_size);
+                       SIVAL(pdata,l1_cbFileAlloc,(uint32_t)allocation_size);
                        SSVAL(pdata,l1_attrFile,mode);
                        break;
 
@@ -4566,8 +4902,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        srv_put_dos_date2(pdata,0,create_time);
                        srv_put_dos_date2(pdata,4,atime);
                        srv_put_dos_date2(pdata,8,mtime); /* write time */
-                       SIVAL(pdata,12,(uint32)file_size);
-                       SIVAL(pdata,16,(uint32)allocation_size);
+                       SIVAL(pdata,12,(uint32_t)file_size);
+                       SIVAL(pdata,16,(uint32_t)allocation_size);
                        SSVAL(pdata,20,mode);
                        SIVAL(pdata,22,ea_size);
                        break;
@@ -4690,6 +5026,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        DEBUG(5,("write: %s ", ctime(&mtime)));
                        DEBUG(5,("change: %s ", ctime(&c_time)));
                        DEBUG(5,("mode: %x\n", mode));
+                       *fixed_portion = data_size;
                        break;
 
                case SMB_FILE_STANDARD_INFORMATION:
@@ -4703,6 +5040,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        SCVAL(pdata,20,delete_pending?1:0);
                        SCVAL(pdata,21,(mode&FILE_ATTRIBUTE_DIRECTORY)?1:0);
                        SSVAL(pdata,22,0); /* Padding. */
+                       *fixed_portion = 24;
                        break;
 
                case SMB_FILE_EA_INFORMATION:
@@ -4712,6 +5050,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                            estimate_ea_size(conn, fsp, smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
                        data_size = 4;
+                       *fixed_portion = 4;
                        SIVAL(pdata,0,ea_size);
                        break;
                }
@@ -4720,32 +5059,37 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                case SMB_QUERY_FILE_ALT_NAME_INFO:
                case SMB_FILE_ALTERNATE_NAME_INFORMATION:
                {
-                       int len;
                        char mangled_name[13];
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
                        if (!name_to_8_3(base_name,mangled_name,
                                                True,conn->params)) {
                                return NT_STATUS_NO_MEMORY;
                        }
-                       len = srvstr_push(dstart, flags2,
+                       status = srvstr_push(dstart, flags2,
                                          pdata+4, mangled_name,
                                          PTR_DIFF(dend, pdata+4),
-                                         STR_UNICODE);
+                                         STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        data_size = 4 + len;
                        SIVAL(pdata,0,len);
+                       *fixed_portion = 8;
                        break;
                }
 
                case SMB_QUERY_FILE_NAME_INFO:
                {
-                       int len;
                        /*
                          this must be *exactly* right for ACLs on mapped drives to work
                         */
-                       len = srvstr_push(dstart, flags2,
+                       status = srvstr_push(dstart, flags2,
                                          pdata+4, dos_fname,
                                          PTR_DIFF(dend, pdata+4),
-                                         STR_UNICODE);
+                                         STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
                        data_size = 4 + len;
                        SIVAL(pdata,0,len);
@@ -4769,7 +5113,6 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                case SMB_QUERY_FILE_ALL_INFO:
                case SMB_FILE_ALL_INFORMATION:
                {
-                       int len;
                        unsigned int ea_size =
                            estimate_ea_size(conn, fsp, smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
@@ -4789,19 +5132,22 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        pdata += 24;
                        SIVAL(pdata,0,ea_size);
                        pdata += 4; /* EA info */
-                       len = srvstr_push(dstart, flags2,
+                       status = srvstr_push(dstart, flags2,
                                          pdata+4, dos_fname,
                                          PTR_DIFF(dend, pdata+4),
-                                         STR_UNICODE);
+                                         STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SIVAL(pdata,0,len);
                        pdata += 4 + len;
                        data_size = PTR_DIFF(pdata,(*ppdata));
+                       *fixed_portion = 10;
                        break;
                }
 
                case 0xFF12:/*SMB2_FILE_ALL_INFORMATION*/
                {
-                       int len;
                        unsigned int ea_size =
                            estimate_ea_size(conn, fsp, smb_fname);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
@@ -4826,13 +5172,17 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
                        pdata += 0x60;
 
-                       len = srvstr_push(dstart, flags2,
+                       status = srvstr_push(dstart, flags2,
                                          pdata+4, dos_fname,
                                          PTR_DIFF(dend, pdata+4),
-                                         STR_UNICODE);
+                                         STR_UNICODE, &len);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
                        SIVAL(pdata,0,len);
                        pdata += 4 + len;
                        data_size = PTR_DIFF(pdata,(*ppdata));
+                       *fixed_portion = 104;
                        break;
                }
                case SMB_FILE_INTERNAL_INFORMATION:
@@ -4840,12 +5190,14 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
                        SBVAL(pdata, 0, file_index);
                        data_size = 8;
+                       *fixed_portion = 8;
                        break;
 
                case SMB_FILE_ACCESS_INFORMATION:
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
                        SIVAL(pdata, 0, access_mask);
                        data_size = 4;
+                       *fixed_portion = 4;
                        break;
 
                case SMB_FILE_NAME_INFORMATION:
@@ -4863,24 +5215,28 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
                        data_size = 1;
                        SCVAL(pdata,0,delete_pending);
+                       *fixed_portion = 1;
                        break;
 
                case SMB_FILE_POSITION_INFORMATION:
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
                        data_size = 8;
                        SOFF_T(pdata,0,pos);
+                       *fixed_portion = 8;
                        break;
 
                case SMB_FILE_MODE_INFORMATION:
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
                        SIVAL(pdata,0,mode);
                        data_size = 4;
+                       *fixed_portion = 4;
                        break;
 
                case SMB_FILE_ALIGNMENT_INFORMATION:
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
                        SIVAL(pdata,0,0); /* No alignment needed. */
                        data_size = 4;
+                       *fixed_portion = 4;
                        break;
 
                /*
@@ -4903,8 +5259,12 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                return NT_STATUS_INVALID_PARAMETER;
                        }
 
-                       status = vfs_streaminfo(conn, fsp, smb_fname->base_name,
-                                               talloc_tos(), &num_streams, &streams);
+                       status = vfs_streaminfo(conn,
+                                               fsp,
+                                               smb_fname,
+                                               talloc_tos(),
+                                               &num_streams,
+                                               &streams);
 
                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(10, ("could not get stream info: %s\n",
@@ -4925,6 +5285,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
                        TALLOC_FREE(streams);
 
+                       *fixed_portion = 32;
+
                        break;
                }
                case SMB_QUERY_COMPRESSION_INFO:
@@ -4934,6 +5296,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        SIVAL(pdata,8,0); /* ??? */
                        SIVAL(pdata,12,0); /* ??? */
                        data_size = 16;
+                       *fixed_portion = 16;
                        break;
 
                case SMB_FILE_NETWORK_OPEN_INFORMATION:
@@ -4947,6 +5310,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        SIVAL(pdata,48,mode);
                        SIVAL(pdata,52,0); /* ??? */
                        data_size = 56;
+                       *fixed_portion = 56;
                        break;
 
                case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
@@ -4954,6 +5318,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        SIVAL(pdata,0,mode);
                        SIVAL(pdata,4,0);
                        data_size = 8;
+                       *fixed_portion = 8;
                        break;
 
                /*
@@ -4989,7 +5354,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
                case SMB_QUERY_FILE_UNIX_LINK:
                        {
-                               int len;
+                               int link_len = 0;
                                char *buffer = talloc_array(mem_ctx, char, PATH_MAX+1);
 
                                if (!buffer) {
@@ -5004,17 +5369,20 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 #else
                                return NT_STATUS_DOS(ERRDOS, ERRbadlink);
 #endif
-                               len = SMB_VFS_READLINK(conn,
+                               link_len = SMB_VFS_READLINK(conn,
                                                       smb_fname->base_name,
                                                       buffer, PATH_MAX);
-                               if (len == -1) {
+                               if (link_len == -1) {
                                        return map_nt_error_from_unix(errno);
                                }
-                               buffer[len] = 0;
-                               len = srvstr_push(dstart, flags2,
+                               buffer[link_len] = 0;
+                               status = srvstr_push(dstart, flags2,
                                                  pdata, buffer,
                                                  PTR_DIFF(dend, pdata),
-                                                 STR_TERMINATE);
+                                                 STR_TERMINATE, &len);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       return status;
+                               }
                                pdata += len;
                                data_size = PTR_DIFF(pdata,(*ppdata));
 
@@ -5026,8 +5394,15 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        {
                                SMB_ACL_T file_acl = NULL;
                                SMB_ACL_T def_acl = NULL;
-                               uint16 num_file_acls = 0;
-                               uint16 num_def_acls = 0;
+                               uint16_t num_file_acls = 0;
+                               uint16_t num_def_acls = 0;
+
+                               status = refuse_symlink(conn,
+                                               fsp,
+                                               smb_fname->base_name);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       return status;
+                               }
 
                                if (fsp && fsp->fh->fd != -1) {
                                        file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp,
@@ -5148,15 +5523,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        }
 
                        smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
-#if defined(HAVE_LONGLONG)
-                       offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
-                                       ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
-                       count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
-                                       ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
-#else /* HAVE_LONGLONG */
-                       offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
-                       count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
-#endif /* HAVE_LONGLONG */
+                       offset = BVAL(pdata,POSIX_LOCK_START_OFFSET);
+                       count = BVAL(pdata,POSIX_LOCK_LEN_OFFSET);
 
                        status = query_lock(fsp,
                                        &smblctx,
@@ -5172,15 +5540,8 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
                                SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
                                SIVAL(pdata, POSIX_LOCK_PID_OFFSET, (uint32_t)smblctx);
-#if defined(HAVE_LONGLONG)
-                               SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
-                               SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
-                               SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
-                               SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
-#else /* HAVE_LONGLONG */
-                               SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
-                               SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
-#endif /* HAVE_LONGLONG */
+                               SBVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
+                               SBVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
 
                        } else if (NT_STATUS_IS_OK(status)) {
                                /* For success we just return a copy of what we sent
@@ -5216,7 +5577,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
 {
        char *params = *pparams;
        char *pdata = *ppdata;
-       uint16 info_level;
+       uint16_t info_level;
        unsigned int data_size = 0;
        unsigned int param_size = 2;
        struct smb_filename *smb_fname = NULL;
@@ -5227,6 +5588,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
        struct ea_list *ea_list = NULL;
        int lock_data_count = 0;
        char *lock_data = NULL;
+       size_t fixed_portion;
        NTSTATUS status = NT_STATUS_OK;
 
        if (!params) {
@@ -5327,7 +5689,8 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
        } else {
                uint32_t name_hash;
                char *fname = NULL;
-               uint32_t ucf_flags = 0;
+               uint32_t ucf_flags = (req->posix_pathnames ?
+                               UCF_POSIX_PATHNAMES : 0);
 
                /* qpathinfo */
                if (total_params < 7) {
@@ -5351,9 +5714,25 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                        }
                }
 
-               srvstr_get_path(req, params, req->flags2, &fname, &params[6],
+               if (req->posix_pathnames) {
+                       srvstr_get_path_posix(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
                                total_params - 6,
-                               STR_TERMINATE, &status);
+                               STR_TERMINATE,
+                               &status);
+               } else {
+                       srvstr_get_path(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
+                               total_params - 6,
+                               STR_TERMINATE,
+                               &status);
+               }
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
@@ -5487,7 +5866,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                case SMB_INFO_QUERY_EAS_FROM_LIST:
                {
                        /* Pull any EA list from the data portion. */
-                       uint32 ea_size;
+                       uint32_t ea_size;
 
                        if (total_data < 4) {
                                reply_nterror(
@@ -5586,11 +5965,16 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
                                       ea_list,
                                       lock_data_count, lock_data,
                                       req->flags2, max_data_bytes,
+                                      &fixed_portion,
                                       ppdata, &data_size);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
        }
+       if (fixed_portion > max_data_bytes) {
+               reply_nterror(req, NT_STATUS_INFO_LENGTH_MISMATCH);
+               return;
+       }
 
        send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size,
                            max_data_bytes);
@@ -5673,7 +6057,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
                           bool setting_write_time)
 {
        struct smb_filename smb_fname_base;
-       uint32 action =
+       uint32_t action =
                FILE_NOTIFY_CHANGE_LAST_ACCESS
                |FILE_NOTIFY_CHANGE_LAST_WRITE
                |FILE_NOTIFY_CHANGE_CREATION;
@@ -5768,7 +6152,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
 
 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
                                     const struct smb_filename *smb_fname,
-                                    uint32 dosmode)
+                                    uint32_t dosmode)
 {
        struct smb_filename *smb_fname_base;
        NTSTATUS status;
@@ -5876,13 +6260,15 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                FILE_OPEN,                              /* create_disposition*/
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
-               FORCE_OPLOCK_BREAK_TO_NONE,             /* oplock_request */
+               0,                                      /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &new_fsp,                               /* result */
-               NULL);                                  /* pinfo */
+               NULL,                                   /* pinfo */
+               NULL, NULL);                            /* create context */
 
        TALLOC_FREE(smb_fname_tmp);
 
@@ -6012,7 +6398,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
 {
        NTSTATUS status = NT_STATUS_OK;
        bool delete_on_close;
-       uint32 dosmode = 0;
+       uint32_t dosmode = 0;
 
        if (total_data < 1) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -6085,7 +6471,7 @@ static NTSTATUS smb_file_mode_information(connection_struct *conn,
                                const char *pdata,
                                int total_data)
 {
-       uint32 mode;
+       uint32_t mode;
 
        if (total_data < 4) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -6118,7 +6504,7 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!lp_symlinks(SNUM(conn))) {
+       if (!lp_follow_symlinks(SNUM(conn))) {
                return NT_STATUS_ACCESS_DENIED;
        }
 
@@ -6150,6 +6536,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
 {
        char *oldname = NULL;
        struct smb_filename *smb_fname_old = NULL;
+       uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
        NTSTATUS status = NT_STATUS_OK;
 
@@ -6158,8 +6545,25 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path(ctx, pdata, req->flags2, &oldname, pdata,
-                       total_data, STR_TERMINATE, &status);
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       pdata,
+                       req->flags2,
+                       &oldname,
+                       pdata,
+                       total_data,
+                       STR_TERMINATE,
+                       &status);
+       } else {
+               srvstr_get_path(ctx,
+                       pdata,
+                       req->flags2,
+                       &oldname,
+                       pdata,
+                       total_data,
+                       STR_TERMINATE,
+                       &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6171,7 +6575,7 @@ static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                oldname,
-                               0,
+                               ucf_flags,
                                NULL,
                                &smb_fname_old);
        if (!NT_STATUS_IS_OK(status)) {
@@ -6197,6 +6601,8 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
        uint32_t len;
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
+       uint32_t ucf_flags = UCF_SAVE_LCOMP |
+               (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        NTSTATUS status = NT_STATUS_OK;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -6215,9 +6621,25 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path(ctx, pdata, req->flags2, &newname,
-                               &pdata[20], len, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
+                               &status);
+       } else {
+               srvstr_get_path(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
                                &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6229,7 +6651,7 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                newname,
-                               UCF_SAVE_LCOMP,
+                               ucf_flags,
                                NULL,
                                &smb_fname_dst);
        if (!NT_STATUS_IS_OK(status)) {
@@ -6289,6 +6711,8 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
        NTSTATUS status = NT_STATUS_OK;
+       uint32_t ucf_flags = UCF_SAVE_LCOMP |
+               (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
 
        if (!fsp) {
@@ -6306,9 +6730,25 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path(ctx, pdata, req->flags2, &newname,
-                               &pdata[20], len, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
+                               &status);
+       } else {
+               srvstr_get_path(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[20],
+                               len,
+                               STR_TERMINATE,
                                &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6320,7 +6760,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                newname,
-                               UCF_SAVE_LCOMP,
+                               ucf_flags,
                                NULL,
                                &smb_fname_dst);
        if (!NT_STATUS_IS_OK(status)) {
@@ -6359,8 +6799,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                                            struct smb_filename *smb_fname_src)
 {
        bool overwrite;
-       uint32 root_fid;
-       uint32 len;
+       uint32_t root_fid;
+       uint32_t len;
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
        bool dest_has_wcard = False;
@@ -6380,9 +6820,27 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       srvstr_get_path_wcard(ctx, pdata, req->flags2, &newname, &pdata[12],
-                             len, 0, &status,
-                             &dest_has_wcard);
+       if (req->posix_pathnames) {
+               srvstr_get_path_wcard_posix(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[12],
+                               len,
+                               0,
+                               &status,
+                               &dest_has_wcard);
+       } else {
+               srvstr_get_path_wcard(ctx,
+                               pdata,
+                               req->flags2,
+                               &newname,
+                               &pdata[12],
+                               len,
+                               0,
+                               &status,
+                               &dest_has_wcard);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6527,11 +6985,12 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
                                files_struct *fsp,
                                const struct smb_filename *smb_fname)
 {
-       uint16 posix_acl_version;
-       uint16 num_file_acls;
-       uint16 num_def_acls;
+       uint16_t posix_acl_version;
+       uint16_t num_file_acls;
+       uint16_t num_def_acls;
        bool valid_file_acls = True;
        bool valid_def_acls = True;
+       NTSTATUS status;
 
        if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -6559,6 +7018,11 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
+       status = refuse_symlink(conn, fsp, smb_fname->base_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
                smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
                (unsigned int)num_file_acls,
@@ -6637,15 +7101,10 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
        }
 
        smblctx = (uint64_t)IVAL(pdata, POSIX_LOCK_PID_OFFSET);
-#if defined(HAVE_LONGLONG)
        offset = (((uint64_t) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
                        ((uint64_t) IVAL(pdata,POSIX_LOCK_START_OFFSET));
        count = (((uint64_t) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
                        ((uint64_t) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
-#else /* HAVE_LONGLONG */
-       offset = (uint64_t)IVAL(pdata,POSIX_LOCK_START_OFFSET);
-       count = (uint64_t)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
-#endif /* HAVE_LONGLONG */
 
        DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
                        "smblctx = %llu, count = %.0f, offset = %.0f\n",
@@ -6674,8 +7133,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
                                                        POSIX_LOCK,
                                                        blocking_lock,
                                                        &status,
-                                                       &block_smblctx,
-                                                       NULL);
+                                                       &block_smblctx);
 
                if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
                        /*
@@ -6716,7 +7174,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
 {
        /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
        struct smb_file_time ft;
-       uint32 dosmode = 0;
+       uint32_t dosmode = 0;
        NTSTATUS status = NT_STATUS_OK;
 
        ZERO_STRUCT(ft);
@@ -6867,13 +7325,15 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
                FILE_OPEN,                              /* create_disposition*/
                0,                                      /* create_options */
                FILE_ATTRIBUTE_NORMAL,                  /* file_attributes */
-               FORCE_OPLOCK_BREAK_TO_NONE,             /* oplock_request */
+               0,                                      /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* allocation_size */
                0,                                      /* private_flags */
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &new_fsp,                               /* result */
-               NULL);                                  /* pinfo */
+               NULL,                                   /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (!NT_STATUS_IS_OK(status)) {
                /* NB. We check for open_was_deferred in the caller. */
@@ -6895,7 +7355,6 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
         * if there are no pending writes.
         */
        trigger_write_time_update_immediate(new_fsp);
-
        close_file(req, new_fsp, NORMAL_CLOSE);
        return NT_STATUS_OK;
 }
@@ -6941,13 +7400,13 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn,
                                        int total_data,
                                        const struct smb_filename *smb_fname)
 {
-       uint32 file_type = IVAL(pdata,56);
+       uint32_t file_type = IVAL(pdata,56);
 #if defined(HAVE_MAKEDEV)
-       uint32 dev_major = IVAL(pdata,60);
-       uint32 dev_minor = IVAL(pdata,68);
+       uint32_t dev_major = IVAL(pdata,60);
+       uint32_t dev_minor = IVAL(pdata,68);
 #endif
        SMB_DEV_T dev = (SMB_DEV_T)0;
-       uint32 raw_unixmode = IVAL(pdata,84);
+       uint32_t raw_unixmode = IVAL(pdata,84);
        NTSTATUS status;
        mode_t unixmode;
 
@@ -7003,7 +7462,7 @@ static NTSTATUS smb_unix_mknod(connection_struct *conn,
         * don't want to end up with a half-constructed mknod.
         */
 
-       if (lp_inherit_perms(SNUM(conn))) {
+       if (lp_inherit_permissions(SNUM(conn))) {
                char *parent;
                if (!parent_dirname(talloc_tos(), smb_fname->base_name,
                                    &parent, NULL)) {
@@ -7029,7 +7488,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                                        const struct smb_filename *smb_fname)
 {
        struct smb_file_time ft;
-       uint32 raw_unixmode;
+       uint32_t raw_unixmode;
        mode_t unixmode;
        off_t size = 0;
        uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
@@ -7142,11 +7601,18 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
         */
 
        if (raw_unixmode != SMB_MODE_NO_CHANGE) {
+               int ret;
+
                DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
                          "setting mode 0%o for file %s\n",
                          (unsigned int)unixmode,
                          smb_fname_str_dbg(smb_fname)));
-               if (SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode) != 0) {
+               if (fsp && fsp->fh->fd != -1) {
+                       ret = SMB_VFS_FCHMOD(fsp, unixmode);
+               } else {
+                       ret = SMB_VFS_CHMOD(conn, smb_fname, unixmode);
+               }
+               if (ret != 0) {
                        return map_nt_error_from_unix(errno);
                }
        }
@@ -7164,12 +7630,15 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                          (unsigned int)set_owner,
                          smb_fname_str_dbg(smb_fname)));
 
-               if (S_ISLNK(sbuf.st_ex_mode)) {
-                       ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name,
-                                            set_owner, (gid_t)-1);
+               if (fsp && fsp->fh->fd != -1) {
+                       ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
                } else {
-                       ret = SMB_VFS_CHOWN(conn, smb_fname->base_name,
-                                           set_owner, (gid_t)-1);
+                       /*
+                        * UNIX extensions calls must always operate
+                        * on symlinks.
+                        */
+                       ret = SMB_VFS_LCHOWN(conn, smb_fname,
+                                            set_owner, (gid_t)-1);
                }
 
                if (ret != 0) {
@@ -7187,12 +7656,23 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
 
        if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) &&
            (sbuf.st_ex_gid != set_grp)) {
+               int ret;
+
                DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
                          "changing group %u for file %s\n",
                          (unsigned int)set_owner,
                          smb_fname_str_dbg(smb_fname)));
-               if (SMB_VFS_CHOWN(conn, smb_fname->base_name, (uid_t)-1,
-                                 set_grp) != 0) {
+               if (fsp && fsp->fh->fd != -1) {
+                       ret = SMB_VFS_FCHOWN(fsp, set_owner, (gid_t)-1);
+               } else {
+                       /*
+                        * UNIX extensions calls must always operate
+                        * on symlinks.
+                        */
+                       ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1,
+                                 set_grp);
+               }
+               if (ret != 0) {
                        status = map_nt_error_from_unix(errno);
                        if (delete_on_fail) {
                                SMB_VFS_UNLINK(conn, smb_fname);
@@ -7264,8 +7744,8 @@ static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
                                        const struct smb_filename *smb_fname)
 {
        NTSTATUS status;
-       uint32 smb_fflags;
-       uint32 smb_fmask;
+       uint32_t smb_fflags;
+       uint32_t smb_fmask;
 
        if (total_data < 116) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -7326,11 +7806,11 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
                                int *pdata_return_size)
 {
        NTSTATUS status = NT_STATUS_OK;
-       uint32 raw_unixmode = 0;
-       uint32 mod_unixmode = 0;
+       uint32_t raw_unixmode = 0;
+       uint32_t mod_unixmode = 0;
        mode_t unixmode = (mode_t)0;
        files_struct *fsp = NULL;
-       uint16 info_level_return = 0;
+       uint16_t info_level_return = 0;
        int info;
        char *pdata = *ppdata;
 
@@ -7347,7 +7827,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
                return status;
        }
 
-       mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+       mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS;
 
        DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
                  smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
@@ -7363,12 +7843,14 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
                FILE_DIRECTORY_FILE,                    /* create_options */
                mod_unixmode,                           /* file_attributes */
                0,                                      /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* 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)) {
                 close_file(req, fsp, NORMAL_CLOSE);
@@ -7434,19 +7916,19 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
 {
        bool extended_oplock_granted = False;
        char *pdata = *ppdata;
-       uint32 flags = 0;
-       uint32 wire_open_mode = 0;
-       uint32 raw_unixmode = 0;
-       uint32 mod_unixmode = 0;
-       uint32 create_disp = 0;
-       uint32 access_mask = 0;
-       uint32 create_options = FILE_NON_DIRECTORY_FILE;
+       uint32_t flags = 0;
+       uint32_t wire_open_mode = 0;
+       uint32_t raw_unixmode = 0;
+       uint32_t mod_unixmode = 0;
+       uint32_t create_disp = 0;
+       uint32_t access_mask = 0;
+       uint32_t create_options = FILE_NON_DIRECTORY_FILE;
        NTSTATUS status = NT_STATUS_OK;
        mode_t unixmode = (mode_t)0;
        files_struct *fsp = NULL;
        int oplock_request = 0;
        int info = 0;
-       uint16 info_level_return = 0;
+       uint16_t info_level_return = 0;
 
        if (total_data < 18) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -7557,7 +8039,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                return status;
        }
 
-       mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+       mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS;
 
        if (wire_open_mode & SMB_O_SYNC) {
                create_options |= FILE_WRITE_THROUGH;
@@ -7595,12 +8077,14 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                create_options,                         /* create_options */
                mod_unixmode,                           /* file_attributes */
                oplock_request,                         /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* 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)) {
                return status;
@@ -7683,7 +8167,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
 {
        NTSTATUS status = NT_STATUS_OK;
        files_struct *fsp = NULL;
-       uint16 flags = 0;
+       uint16_t flags = 0;
        char del = 1;
        int info = 0;
        int create_options = 0;
@@ -7725,12 +8209,14 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                create_options,                         /* create_options */
                FILE_FLAG_POSIX_SEMANTICS|0777,         /* file_attributes */
                0,                                      /* oplock_request */
+               NULL,                                   /* lease */
                0,                                      /* 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)) {
                return status;
@@ -8086,7 +8572,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
 {
        char *params = *pparams;
        char *pdata = *ppdata;
-       uint16 info_level;
+       uint16_t info_level;
        struct smb_filename *smb_fname = NULL;
        files_struct *fsp = NULL;
        NTSTATUS status = NT_STATUS_OK;
@@ -8178,7 +8664,8 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                }
        } else {
                char *fname = NULL;
-               uint32_t ucf_flags = 0;
+               uint32_t ucf_flags = (req->posix_pathnames ?
+                       UCF_POSIX_PATHNAMES : 0);
 
                /* set path info */
                if (total_params < 7) {
@@ -8187,9 +8674,25 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                }
 
                info_level = SVAL(params,0);
-               srvstr_get_path(req, params, req->flags2, &fname, &params[6],
-                               total_params - 6, STR_TERMINATE,
+               if (req->posix_pathnames) {
+                       srvstr_get_path_posix(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
+                               total_params - 6,
+                               STR_TERMINATE,
                                &status);
+               } else {
+                       srvstr_get_path(req,
+                               params,
+                               req->flags2,
+                               &fname,
+                               &params[6],
+                               total_params - 6,
+                               STR_TERMINATE,
+                               &status);
+               }
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
@@ -8260,7 +8763,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                                         ppdata, total_data,
                                         &data_return_size);
        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. */
                        return;
                }
@@ -8312,6 +8815,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
        char *directory = NULL;
        NTSTATUS status = NT_STATUS_OK;
        struct ea_list *ea_list = NULL;
+       uint32_t ucf_flags = (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
        TALLOC_CTX *ctx = talloc_tos();
 
        if (!CAN_WRITE(conn)) {
@@ -8324,9 +8828,25 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                return;
        }
 
-       srvstr_get_path(ctx, params, req->flags2, &directory, &params[4],
-                       total_params - 4, STR_TERMINATE,
+       if (req->posix_pathnames) {
+               srvstr_get_path_posix(ctx,
+                       params,
+                       req->flags2,
+                       &directory,
+                       &params[4],
+                       total_params - 4,
+                       STR_TERMINATE,
                        &status);
+       } else {
+               srvstr_get_path(ctx,
+                       params,
+                       req->flags2,
+                       &directory,
+                       &params[4],
+                       total_params - 4,
+                       STR_TERMINATE,
+                       &status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;
@@ -8338,7 +8858,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                directory,
-                               0,
+                               ucf_flags,
                                NULL,
                                &smb_dname);
 
@@ -8435,7 +8955,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn,
                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
-       uint16 info_level;
+       uint16_t info_level;
 
        if (total_params < 6) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -8572,6 +9092,8 @@ static void call_trans2ioctl(connection_struct *conn,
 {
        char *pdata = *ppdata;
        files_struct *fsp = file_fsp(req, SVAL(req->vwv+15, 0));
+       NTSTATUS status;
+       size_t len = 0;
 
        /* check for an invalid fid before proceeding */
 
@@ -8595,12 +9117,20 @@ static void call_trans2ioctl(connection_struct *conn,
                /* Job number */
                SSVAL(pdata, 0, print_spool_rap_jobid(fsp->print_file));
 
-               srvstr_push(pdata, req->flags2, pdata + 2,
+               status = srvstr_push(pdata, req->flags2, pdata + 2,
                            lp_netbios_name(), 15,
-                           STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
-               srvstr_push(pdata, req->flags2, pdata+18,
+                           STR_ASCII|STR_TERMINATE, &len); /* Our NetBIOS name */
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+               status = srvstr_push(pdata, req->flags2, pdata+18,
                            lp_servicename(talloc_tos(), SNUM(conn)), 13,
-                           STR_ASCII|STR_TERMINATE); /* Service name */
+                           STR_ASCII|STR_TERMINATE, &len); /* Service name */
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
                send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32,
                                    max_data_bytes);
                return;